send和recv (大文件传输)

来源:互联网 发布:mac系统怎么安装ae插件 编辑:程序博客网 时间:2024/04/30 10:49

实验环境:

        Windows

实验目的:

        使用socket传输大文件(19.4M)


实验过程:

    第一阶段

        1.Server使用send(s,buffer,dataLen,0)将文件装入buffer一次发送出去

           结果:成功

        2.Client端使用char ch[20*1024*1024] = {0}开出20M栈空间以接数据

           结果:栈溢出

          

          应对方法:

                使用堆分配char *ch = new char[20*1024*1024]

        3.Client接收数据int ret = recv(s,ch,20*1024*1024,0)

           结果:recv只接了27K数据,Server中send显示发送数据为19.4M

        4.Client采用循环接收,不断的recv

           结果:文件传输成功


    第二阶段

        5.本机开Server,Client跑在其它电脑

           结果:Client接收失败

        6.在Client的循环接收中加入输出,打印差多少字节

           结果:循环输出42

               分析原因:

                    Server在send mfc.zip之前先send了8字节文件长度,Client在recv mfc.zip前先使用50字节长的缓冲区tmp[50] recv了长度,推断:差                                 的42字节被tmp收走

               验证:

                    添加输出,在recv长度处打印此次接收的长度

               结果:

                    输出50,Server send发送长度设置正确

        7.将tmp的后42字节加入buffer中并修改代码

           结果:成功


特殊现象概述:

        发送方:send两次,第一次send 8字节,第二次send 19.4M

        接收方:8字节在前、19.4M在后,两部分合二为一、一起到达


实验结论:

        1.系统发送缓冲区一定很大,即send(s,buffer,dataLen,0)19.4M一次发送没有问题。

        2.系统接收缓冲区有限制,即recv(s,buffer,bufferLen,0)不管buffer多大一次只能几十到上百K,只有循环接收才能解决。

        3.小数据发送会产生粘包。


附加内容:

        1.send函数

                int send(SOCKET s, const char *buffer, int len, int flag)

               数据从buffer拷贝到transport buffer,然后进行发送。len大小为多少便发送多少的数据。

        2.程序栈和堆的大小

                linux系统下默认栈大小是10M,windows系统下默认栈大小是1M.
                windows下用vs2010编译C++程序时,编译属性中可以重新设定栈大小.
                堆的话,理论上内存有多大,就可以建多大.
                但32位的程序在64位系统上运行的时候,一个进程的堆大小应该是不可以超过4G的.

                栈和线程相关, 默认1MB预留, 初次递交8KB, 自动增长, 具体使用要看线程调用栈了. 所以如果进程中有N个线程. 默认情况下, 有N*1MB的栈预留                 空间, 和小于这个数字的实际使用.
                堆和Heap管理有关, 默认存在系统堆和CRT堆. 具体大小取决于程序本身对内存的分配和使用, 可以调用HeapSize看实际使用大小. 
                另外还有虚拟内存, 独立于对堆外, 直接通过VirtualAlloc预留或分配. 也属于进程动态分配的内存.


实验代码:

Server

#include <WinSock2.h>#include <Windows.h>#include <iostream>#include <string>#include <fstream>#pragma comment(lib, "Ws2_32.lib")int main(){WSADATA ws;if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)return false;SOCKET s = socket(AF_INET, SOCK_STREAM, 0);if(INVALID_SOCKET == s)return false;SOCKADDR_INaddr;addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addr.sin_port = htons(4444);int ret = bind(s, (sockaddr*)&addr, sizeof(addr));if(SOCKET_ERROR == ret){std::cout<<"bind failed : "<<GetLastError()<<std::endl;return SOCKET_ERROR;}ret = listen(s, 10);if(SOCKET_ERROR == s){std::cout<<"listen fail : "<<GetLastError()<<std::endl;return SOCKET_ERROR;}while(true){SOCKADDR_IN clientAddr;int addrLen = sizeof(clientAddr);SOCKET cs = accept(s, (sockaddr*)&clientAddr, &addrLen);if(INVALID_SOCKET == cs){std::cout<<"accept failed : "<<GetLastError()<<std::endl;continue;}std::cout<<"one connection enter into..."<<std::endl;{char buf[1024] = {0};ret = recv(cs, buf, 1024, 0);if(SOCKET_ERROR == ret){std::cout<<"recv error : "<<GetLastError()<<std::endl;continue;}std::cout<<buf<<std::endl;}{char buf[] = "hello baby\r\n";ret = send(cs, buf, strlen(buf), 0);if(SOCKET_ERROR == ret){std::cout<<"send error : "<<GetLastError()<<std::endl;return -1;}}{std::ifstream is("C:\\Documents and Settings\\Administrator\\桌面\\mfc.zip", std::ios::binary);is.seekg(0, is.end);int length = is.tellg();is.seekg(0, is.beg);char *ch = new char[length+10];std::string str = std::to_string((long long)length);memset(ch, 0, 10);memcpy(ch, str.c_str(), str.length());is.read(ch+10, length);ret = send(cs, ch, length+10, 0);if(SOCKET_ERROR == ret){std::cout<<"send large data error : "<<GetLastError()<<std::endl;return -1;}delete []ch;is.close();}Sleep(10000);closesocket(cs);}return 0;}

Client

#include <WinSock2.h>#include <Windows.h>#include <iostream>#include <fstream>#include <string>#include <process.h>#pragma comment(lib, "Ws2_32.lib")int main(){WSADATA ws;if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)return false;SOCKET s = socket(AF_INET, SOCK_STREAM, 0);if(INVALID_SOCKET == s)return false;sockaddr_in addr = {0};addr.sin_addr.S_un.S_addr = inet_addr("192.168.4.18");addr.sin_family = AF_INET;addr.sin_port = htons(4444);int ret = connect(s, (sockaddr*)&addr, sizeof(addr));if(SOCKET_ERROR == ret){std::cout<<"Connect Server Failed : "<<GetLastError()<<std::endl;return -1;}std::string str = "xiaogushihaoren";ret = send(s, str.c_str(), str.length(), 0);if(SOCKET_ERROR  == ret){std::cout<<"Send Data Failed : "<<GetLastError()<<std::endl;return -1;}char ch[100] = {0};ret = recv(s, ch, 100, 0);if(0 == ret){std::cout<<"Peer Close The Connection"<<std::endl;return -1;}else if(SOCKET_ERROR == ret){std::cout<<"Recv Data Failed : "<<GetLastError()<<std::endl;return -1;}std::cout<<ch<<std::endl;{char tmp[10] = {0};ret = recv(s, tmp, 10, 0);int len = std::stoi(tmp);char *chmax = new char[len];int cursor = 0;while(cursor != len){char ch[100*1024] = {0};ret = recv(s, ch, 100*1024, 0);if(SOCKET_ERROR == ret){std::cout<<"Recv Data Failed : "<<GetLastError()<<std::endl;return -1;}if(0 == ret)break;memcpy(chmax+cursor, ch, ret);cursor += ret;}std::ofstream os("C:\\mfc1.zip", std::ios::binary);os.write(chmax, len);os.close();}std::cin.get();return 0;}


0 0
原创粉丝点击