基于ftp的多线程Socket编程,服务器端和客户端可以互传文件。
编译环境:VS2019,VC++
先在D盘添加file_server和file_client文件夹,在里面可以新建一些文件,方便客户端上传与下载。
有注释,贴上源码,供大家学习参考。
服务器端 Server.cpp
#include <windows.h> #include <stdio.h> #include<iostream> #include <string.h> #pragma comment (lib,"ws2_32") using namespace std; #define BUF_SIZE 1024 void RecvFile(char name[], SOCKET s) { char FileName[MAXBYTE] = ""; sprintf(FileName, "D:\file_server\%s", name); char info[BUF_SIZE]; recv(s, info, BUF_SIZE, 0); cout << info << endl; if (!strcmp(info, "传输文件失败, 文件不存在! ")) { } else { DWORD dwWrite; HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); char szBufferfile[BUF_SIZE] = { NULL }; char ok[BUF_SIZE] = { NULL }; while (true) { int read = recv(s, szBufferfile, BUF_SIZE, 0); if (!strcmp(ok, szBufferfile)) { printf("接收文件成功!!! "); break; } bool bRet = WriteFile(hFile, szBufferfile, read, &dwWrite, NULL); } CloseHandle(hFile); } } void Sender(char name[], SOCKET clientSock) { char FileName[MAXBYTE] = ""; sprintf(FileName, "D:\file_server\%s", name); char ok[BUF_SIZE] = { NULL }; char SendBuf[BUF_SIZE] = { NULL }; DWORD dwRead; HANDLE hFile = CreateFile(FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { send(clientSock, "传输文件失败, 文件不存在! ", BUF_SIZE, 0); } else { send(clientSock, "开始接收文件 ", BUF_SIZE, 0); while (TRUE) { bool bRet = ReadFile(hFile, SendBuf, BUF_SIZE, &dwRead, NULL); if (bRet == FALSE) { //MessageBox(NULL, "Read Buf ERROR!", "Error", MB_OK); CloseHandle(hFile); break; } else if (dwRead == 0) { //MessageBox(NULL, "Send file OK!", "OK", MB_OK); CloseHandle(hFile); printf("发送文件成功!!! "); send(clientSock, ok, BUF_SIZE, 0); break; } else { send(clientSock, SendBuf, BUF_SIZE, 0); } } } } DWORD WINAPI ClientThread(LPVOID IpParam) { SOCKET clientSock = (SOCKET)IpParam; printf("与客户端取得连接,套接字编号为%u ", clientSock); char RecvBuf[MAXBYTE]; char FileName[MAXBYTE] = { NULL }; int read = 0; char getcheck[6] = { "down" }; char upcheck[6] = { "up" }; while (true) { memset(RecvBuf, 0, MAXBYTE);//与客户端进行文字通信 read = recv(clientSock, RecvBuf, MAXBYTE, 0); if (read == -1) break; printf(RecvBuf); printf(" "); if (!strcmp(RecvBuf, getcheck)) { // get 下载文件 memset(FileName, 0, MAXBYTE); read = recv(clientSock, FileName, MAXBYTE, 0); if (read == -1) break; printf("%s ", FileName); Sender(FileName, clientSock); } else if (!strcmp(RecvBuf, upcheck)) { memset(FileName, 0, MAXBYTE); recv(clientSock, FileName, MAXBYTE, 0); RecvFile(FileName, clientSock); } else { send(clientSock, "无效的命令,请重新输入.. ", MAXBYTE, NULL); } } closesocket(clientSock); return 0; } int main(int argc, char* argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //套接字s用于监听 sockaddr_in sockaddr; sockaddr.sin_family = PF_INET; sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); sockaddr.sin_port = htons(827); bind(s, (SOCKADDR*)&sockaddr, sizeof(sockaddr)); //绑定套接字 ip,端口号 SOCKADDR clientAddr = { 0 }; int nSize = sizeof(SOCKADDR); SOCKET clientSock; listen(s, 1); //循环接受客户端连接请求,并生成线程去处理: printf("I'm server "); while(1) { //等待接受客户端控制连接请求 clientSock = accept(s, (SOCKADDR*)&clientAddr, &nSize); //创建一个线程来处理相应客户端的请求: DWORD dwThreadId, dwThrdParam = 1; HANDLE hThread; hThread = CreateThread( NULL, //无需安全性的继承 0, //默认线程栈大小 ClientThread, //线程入口函数 (LPVOID)clientSock, //线程入口函数的参数 0, //立即启动线程 &dwThreadId); //返回线程的id值 //检查返回值是否创建线程成功 if (hThread == NULL) { printf("创建线程失败。 "); closesocket(s); } CloseHandle(hThread); } closesocket(clientSock); closesocket(s); WSACleanup(); return 0; }
客户端 Client.cpp
#include<iostream> #include<winsock2.h> #pragma comment (lib,"ws2_32") using namespace std; #define BUF_SIZE 1024 void RecvFile(char name[], SOCKET s) { char FileName[MAXBYTE] = ""; sprintf(FileName, "D:\file_client\%s", name); char info[BUF_SIZE]; recv(s, info, BUF_SIZE, 0); cout << info << endl; if (!strcmp(info, "传输文件失败, 文件不存在! ")) { } else { DWORD dwWrite; HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); char szBufferfile[BUF_SIZE] = { NULL }; char ok[BUF_SIZE] = { NULL }; while (true) { int read = recv(s, szBufferfile, BUF_SIZE, 0); if (!strcmp(ok, szBufferfile)) { printf("已接收到文件!!! "); break; } bool bRet = WriteFile(hFile, szBufferfile, read, &dwWrite, NULL); } CloseHandle(hFile); printf("写入文件成功!!! "); } } void Sender(char name[], SOCKET clientSock) { char FileName[MAXBYTE] = ""; sprintf(FileName, "D:\file_client\%s", name); char ok[BUF_SIZE] = { NULL }; char SendBuf[BUF_SIZE] = { NULL }; DWORD dwRead; HANDLE hFile = CreateFile(FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { cout << "传输文件失败, 文件不存在!" << endl; send(clientSock, "传输文件失败, 文件不存在! ", BUF_SIZE, 0); } else { send(clientSock, "开始接收文件... ", BUF_SIZE, 0); while (TRUE) { bool bRet = ReadFile(hFile, SendBuf, BUF_SIZE, &dwRead, NULL); if (bRet == FALSE) { //MessageBox(NULL, "Read Buf ERROR!", "Error", MB_OK); CloseHandle(hFile); break; } else if (dwRead == 0) { //MessageBox(NULL, "Send file OK!", "OK", MB_OK); CloseHandle(hFile); printf("发送文件成功!!! "); send(clientSock, ok, BUF_SIZE, 0); break; } else { send(clientSock, SendBuf, BUF_SIZE, 0); } } } } int main(int argc, char* argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //创建套接字 sockaddr_in sockAddr; sockAddr.sin_family = PF_INET; sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(827); char SendBuf[MAXBYTE]; char szBuffer[MAXBYTE] = { NULL }; char FileName[MAXBYTE] = { NULL }; char getcheck[6] = { "down" }; char upcheck[6] = { "up" }; char bye[6] = { "exit" }; printf("I'm Client 1)down:从服务端下载文件 2)up:上传文件到服务器 3)exit:退出 "); //cout << "Server:" << endl; connect(s, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); //给服务器端发送TCP链接请求 while (TRUE) { cout << "Client:"; memset(SendBuf, 0, MAXBYTE); cin >> SendBuf; if (!strcmp(SendBuf, getcheck)) { send(s, SendBuf, MAXBYTE, NULL); cout << "filename:"; memset(FileName, 0, MAXBYTE); cin >> FileName; send(s, FileName, MAXBYTE, NULL); RecvFile(FileName, s); continue; } else if (!strcmp(SendBuf, upcheck)) { send(s, SendBuf, MAXBYTE, NULL); cout << "filename:"; memset(FileName, 0, MAXBYTE); cin >> FileName; send(s, FileName, MAXBYTE, NULL); Sender(FileName, s); continue; } else if (!strcmp(SendBuf, bye)) { cout << "已退出。 " << endl; break; } send(s, SendBuf, MAXBYTE, NULL); memset(szBuffer, 0, MAXBYTE); memset(SendBuf, 0, MAXBYTE); recv(s, szBuffer, MAXBYTE, NULL); cout << szBuffer; } closesocket(s); WSACleanup(); return 0; }