//Server ..... // tServer.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <winsock.h> #include <stdio.h> #include <string> using namespace std; #define PORT 8080 #define MSGSIZE (64*1024) // 64KB #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; SOCKET g_CliSocketArr[FD_SETSIZE]; DWORD WINAPI WorkerThread(LPVOID lpParameter); int main() { WSADATA wsaData; SOCKET sListen, sClient; SOCKADDR_IN local, client; int iaddrSize = sizeof(SOCKADDR_IN); DWORD dwThreadId; // Windows异步套接字)的启动命令 if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL { printf("Winsock无法初始化!\n"); WSACleanup(); return 0; } // Create listening socket sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Bind local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); local.sin_family = AF_INET; local.sin_port = ::htons(PORT); bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN)); // Listen ::listen(sListen, 3); printf("Server is listening!\n"); while (TRUE) { // Accept a connection sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize); printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); // Create worker thread CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId); // Add socket to g_CliSocketArr g_CliSocketArr[g_iTotalConn++] = sClient; } return 0; } // fd_set set; // FD_ZERO(&set); 将set清零使集合中不含任何fd // FD_SET(fd, &set); 将fd加入set集合 // FD_CLR(fd, &set); 将fd从set集合中清除 // FD_ISSET(fd, &set); 测试fd是否在set集合中 DWORD WINAPI WorkerThread(LPVOID lpParam) { printf("WorkerThread\n"); int i; fd_set fdreadset; int ret; struct timeval tv = {1, 0}; char szMessage[MSGSIZE]; __int64 sumRev = 0; string newPath = "./new.avi"; HANDLE hOut = ::CreateFile(newPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if ( INVALID_HANDLE_VALUE == hOut ) { perror("open out file"); return 0; } while (TRUE) { // printf(". "); FD_ZERO(&fdreadset); for (i = 0; i < g_iTotalConn; i++) { FD_SET(g_CliSocketArr[i], &fdreadset); } // We only care read event // 非阻塞... ret = select(0, &fdreadset, NULL, NULL, &tv); if (ret == 0) { // Time expired continue; } for (i = 0; i < g_iTotalConn; i++) { if (FD_ISSET(g_CliSocketArr[i], &fdreadset)) { // A read event happened on g_CliSocketArr memset(szMessage,0,MSGSIZE); ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0); if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)) { // Client socket closed printf("Client socket %d closed.\n\n", g_CliSocketArr); closesocket(g_CliSocketArr[i]); FD_CLR(g_CliSocketArr[i], &fdreadset); if (i < g_iTotalConn - 1) { g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn]; } else { --g_iTotalConn; } cout<<"rev = "<<sumRev/1024/1024<<"MB"<<endl; CloseHandle(hOut); ::ExitThread(0); } else if(ret > 0) { sumRev += ret; //cout<<"r = "<<ret/1024<<"KB"<<endl; DWORD wsize; //char tmpMes[] if (::WriteFile(hOut, szMessage, ret, &wsize, 0) != TRUE ) { perror("write"); break; } //cout<<"w = "<<wsize/1024<<"KB"<<endl; //printf("write over.\n"); } } //if }//for }//while return 0; }
// Client.... #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <WinSock2.h> #include <iostream> #include <WinBase.h> #include <string> using namespace std; #define IPMSG_DEFAULT_VIEWMAX (8 * 1024 * 1024) // 8MB #define IPMSG_DEFAULT_TCPBUFMAX (256 * 1024) // 256KB // 网络链接库 #pragma comment( lib , "ws2_32.lib") DWORD mlastTick = 0; bool SendFile(int sockfd) { // 打开文件 const string orgPath = "./abcd.avi"; HANDLE hIn = ::CreateFile(orgPath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if ( INVALID_HANDLE_VALUE == hIn ) { perror("open in file"); return false; } // 获取文件大小 DWORD dwInFileSizeHigh = 0; __int64 qwInFileSize = ::GetFileSize(hIn, &dwInFileSizeHigh); qwInFileSize |= (((__int64)dwInFileSizeHigh) << 32); // 创建文件映射 HANDLE hInMapFile = ::CreateFileMapping(hIn, NULL, PAGE_READONLY, 0, 0, NULL); if ( INVALID_HANDLE_VALUE == hInMapFile ) { ::CloseHandle(hIn); return false; } __int64 remain = qwInFileSize; __int64 offset = 0; // 调整映射 while(remain > 0) { printf("next block\n"); cout<<"offset = "<<offset<<endl; // 映射下一块,一次8M char* pInMapAddress = (char *)::MapViewOfFile(hInMapFile, FILE_MAP_READ, (int)(offset >> 32), (int)offset, (int)(remain > IPMSG_DEFAULT_VIEWMAX ? IPMSG_DEFAULT_VIEWMAX : remain)); if(NULL == pInMapAddress) { perror("MapViewOfFile!"); ::CloseHandle(hIn); return false; } int size = ::send(sockfd, pInMapAddress, (DWORD)(remain > IPMSG_DEFAULT_VIEWMAX ? IPMSG_DEFAULT_VIEWMAX : remain), 0); if(size == -1) { perror("send error!"); return false; } offset += remain > IPMSG_DEFAULT_VIEWMAX ? IPMSG_DEFAULT_VIEWMAX : remain; remain -= remain > IPMSG_DEFAULT_VIEWMAX ? IPMSG_DEFAULT_VIEWMAX : remain; // 计算新的剩余量 cout<<"offset = "<<offset<<" size = "<<size<<" remain = "<<remain<<endl; ::UnmapViewOfFile(pInMapAddress); // 删除旧的映射 // 更新总消耗时间 DWORD lastTick = ::GetTickCount(); DWORD t = lastTick - mlastTick; mlastTick = lastTick; cout<<"t = "<<t<<endl<<endl; } ::CloseHandle(hIn); return TRUE; } int main(int argc,char *argv[]) { // Windows异步套接字)的启动命令 WSADATA wsaData; if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL { printf("Winsock无法初始化!\n"); WSACleanup(); return 0; } int sockfd,numbytes; char buf[100]; struct sockaddr_in their_addr; //建立一个TCP套接口 if((sockfd = ::socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); printf("create socket error.建立一个TCP套接口失败"); exit(1); } // 初始化socket Buffer int TcpbufMax = IPMSG_DEFAULT_TCPBUFMAX; for (int buf_size = TcpbufMax; buf_size > 0; buf_size /= 2) { if (::setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(buf_size)) == 0) { break; } } //初始化结构体,连接到服务器的8080端口 their_addr.sin_family = AF_INET; their_addr.sin_port = htons(8080); hostent *pEnt; char hostname[256]; ::gethostname(hostname, sizeof(hostname)); if ((pEnt = ::gethostbyname(hostname)) != NULL) { ULONG ad = *(ULONG *)pEnt->h_addr_list[0]; their_addr.sin_addr.s_addr = inet_addr("10.1.37.232"); //std::cout<<ad<<std::endl; } memset(their_addr.sin_zero,0,8); //和服务器建立连接 if(::connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1) { perror("connect"); exit(1); } SendFile(sockfd); //关闭socket closesocket(sockfd); getchar(); }
飞鸽的传输过程中, 客户端发送文件, 使用了文件的内存映射, 可以加快文件的读入.
本人实验了下, 局域网内每秒1.2M左右., 没有飞鸽传的快. 不太理想,
服务器端,使用了::select()函数, 实现非阻塞式连接..
代码还有待改进, 望高手指点...