參考飛鴿傳書的檔案傳輸,實現用戶端與伺服器端的串連

來源:互聯網
上載者:User
//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()函數, 實現非阻塞式串連..

代碼還有待改進, 望高手指點...

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.