socket分包小实验

当采用最基本socket来传输数据时,如果接受方的缓存去足够大,一次就能保存全部数据;但是当传输的数据比较大(像视频,大文件等),这个时候数据明显需要多次传输。下面是演示将数据分开多次发送的一个例子,分包的关键就是自己设定一套规则,将要发送的数据按照规则组织在一起。有一个要注意的地方:如果发送的数据小于接受方的缓冲区大小,分包就没有意义了;所以接受方缓冲区的大小应该和发送包的最大size相等。
服务端:

#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
int main(int argc, char* argv[])
{
    sockaddr_in remoteAddr; 
    sockaddr_in sin;
    SOCKET sClient;
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(2, 2);

    int nAddrLen = sizeof(remoteAddr),ret=0,size=0;
    char revData[18]={0},*buff="\r\n编程,我来了\r\n",Data[0x1008]={0x04,0x01};

    //加载winsock库
    if(WSAStartup(sockVersion, &wsaData) != 0)
        return 0;
    // 创建套节字
    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sListen == INVALID_SOCKET)
    {
        printf("socket error\n");
        return 0;
    }   
    // 在sockaddr_in结构中装入地址信息
    sin.sin_family = AF_INET;
    sin.sin_port = htons(4500); // htons函数 将主机的无符号短整形数转换成网络
    //字节顺序
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    // 使套接字和本地地址绑定
    if(bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf(" bind error \n");
        closesocket(sListen);
        return 0;
    }
    // 设置套接字进入监听模式
    if(listen(sListen, 5) == SOCKET_ERROR)
    {
        printf("listen error\n");
        closesocket(sListen);
        return 0;
    }
    sClient = accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);
    if(sClient == INVALID_SOCKET)
    {
        printf("accept() error");
        return 0;
    }
    printf(" 接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
    do
    {
        ret=recv(sClient,revData,18,0);//缓冲区大小为18
        if(ret>0)
        {   
            memcpy(Data+size,revData+2,16);//接受包中前2个字节是标记,后面是有效数据
            size+=(ret-2);
        }
        if(revData[1]==0x01)//收到最后一个包,数据接受完毕
              break;
        memset(revData,0,18);
    }while(1);
    printf("recv is %s\n",Data);
    send(sClient,buff,strlen(buff),0);
    // 关闭套接字句柄,结束会话
    closesocket(sClient);
    closesocket(sListen);
    WSACleanup();
    return 0;
}

客户端:

#include<stdio.h>
#include<windows.h>
#pragma comment(lib,"ws2_32")
int main()
{
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(2, 2);
    int DataSize=0,num=0,ret=0;
    char revData[255],
        buff[0x100]="abcdxxxx xxxefghijklmn2288ostua0vwaxyzxxx xxxx11111111\n",
        sendData[0x1008]={0x04,0x01};

    //加载winsock库
    if(WSAStartup(sockVersion, &wsaData) != 0)
        return 0;
    SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sClient == INVALID_SOCKET)
    {
        printf("socket error\n");
        return 0;
    }   
    sockaddr_in servAddr;
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(4500);// htons函数 将主机的无符号短整形数转换成网络
                                    //字节顺序,4500端口为要连接服务器端的端口
    servAddr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");//服务器端ip
    if(connect(sClient,(sockaddr*)&servAddr,sizeof(servAddr))==SOCKET_ERROR)
    {
        printf("connect error\n");
        closesocket(sClient);
        return 0;
    }
    DataSize=strlen(buff);
    do
    {
        if(DataSize>16)//还有数据
        {
            memcpy(sendData+2,buff+16*(num++),16);
            sendData[1]=0x0;//设置第2个字节为0x0,表示中间包
            send(sClient,sendData,18,0);
        }
        else //最后一个包 
        {
            memcpy(sendData+2,buff+16*(num),DataSize);
            sendData[1]=0x01;//设置第2个字节为0x1,表示最后一个包
            send(sClient,sendData,DataSize+2,0);
        }
        DataSize-=16; //two bytes per time 
    }while(DataSize>0);
    //直到收到有效数据时才打印出来
    ret=recv(sClient,revData,255,0);
    if(ret>0)
    {
        //为了防止打印出错,把字符串结尾设成0x00
        revData[ret]=0x00;
        printf(revData);
    }
    closesocket(sClient);
    WSACleanup();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值