首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

参照飞鸽传书的文件传输,实现客户端与服务器端的连接

2012-08-22 
参考飞鸽传书的文件传输,实现客户端与服务器端的连接//Server .....// tServer.cpp : Defines the entry p

参考飞鸽传书的文件传输,实现客户端与服务器端的连接

//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;DWORDwsize;//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 }//whilereturn 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;// 映射下一块,一次8Mchar* 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);returnTRUE;}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 Bufferint 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);//关闭socketclosesocket(sockfd);getchar();}


飞鸽的传输过程中, 客户端发送文件, 使用了文件的内存映射,  可以加快文件的读入.

本人实验了下, 局域网内每秒1.2M左右., 没有飞鸽传的快. 不太理想,

 

服务器端,使用了::select()函数, 实现非阻塞式连接..

代码还有待改进, 望高手指点...

热点排行