freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

基于UDP协议实现GB级文件传输
2021-10-14 14:57:22

前言

UDP,全称 User Datagram Protocol,中文名称为用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络连接。UDP 协议从问世至今已经被使用了很多年,虽然目前 UDP 协议的应用不如 TCP 协议广泛,但 UDP 依然是一种非常实用和可行的网络传输层协议。尤其是在一些实时性很强的应用场景中,比如网络游戏、视频会议等,UDP 协议的快速能力更具有独特的魅力。

关键字:Linux socket UDP GB级 文件传输


  • 服务器端

    • 使用socket()函数加载套接字库,创建套接字;

    • 使用bind()函数来绑定套接字到一个IP地址和一个端口上;

    • 使用Listen()函数将套接字设置为监听模式,等待连接请求;

    • 用accept()函数接受连接请求,返回一个新的对应于连接的套接字;

    • 用send()/sendto()函数返回的套接字和客户端进行通信;

    • 返回到第三步,等待另一个请求;

    • 用closesocket()函数关闭套接字。

  • 客户端

    • 使用socket()函数加载套接字库,创建套接字;

    • 使用connect()函数向服务器发出连接请求;

    • 用send()/recv()函数与服务器端进行通信;

    • 通信完成后,用closesocket()函数关闭套接字。


服务器

创建套接字

int sockfd;

if((sockfd = socket(AF_INET,SOCK_DGRAM,0))<0)
{
    printf("socket build error!\n");
}
else
{
    printf("socket build success!\n");
}

socket是一个函数,那么它也有返回值,当套接字创建成功时,返回套接字,失败返回“-1”,错误代码则写入errno中。AF_INET表示IPv4,SOCK_DGRAM数据传输方式 注:TCP使用的是流套接字(SOCK_STREAM),UDP使用的是数据报套接字(SOCK_DGRAM

绑定套接字到一个IP地址和一个端口上

struct sockaddr_in server
memset(&server,0,sizeof(server));  //清空server结构体
server.sin_family= AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(8888);

if((bind(sockfd,(struct sockaddr*)&server,sizeof(server)))==-1)
{
    printf("bind error!\n");
}
else
{
    printf("bind success!\n");
}

sockaddr_in是一个数据结构;用做bindconnectrecvfromsendto等函数的参数,指明地址信息sin_family表示地址类型,对于基于TCP/IP传输协议的通信,该值只能是AF_INETsin_prot表示端口号,例如:21 或者 80 或者 27015,总之在0 ~ 65535之间;sin_addr表示32位的IP地址,例如:192.168.1.5 或 202.96.134.133;sin_zero表示填充字节,一般情况下该值为0;bind()函数int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen);

bind()函数通过给一个套接字接口分配一个地址来建立捆绑。

接收客户端数据

从客户端接收文件名
struct sockaddr_in client;
int addrlen=sizeof(struct sockaddr);
printf("waiting....\n");
        memset(filename,'\0',sizeof(filename));
        memset(filepath,'\0',sizeof(filepath));
        lenfilepath = recvfrom(sockfd,filepath,100,0,(struct sockaddr *)&client,&addrlen);
        printf("filepath :%s\n",filepath);
if(lenfilepath=1)
{ printf("recv finished!\n");}
从客户端接收文件
while(fileTrans =recvfrom(sockfd,buffer,BUFFER_SIZE,0,(struct sockaddr *)&client,&addrlen))
{
printf("data= %d   ",data);
data++;
                if(fileTrans<0)
                {
                    printf("recv2 error!\n");
                    break;
                }

                writelength = fwrite(buffer,sizeof(char),fileTrans,fp);

                if(fileTrans < BUFFER_SIZE)
                {
                    printf("finish writing!\n");
                    break;
                }else{
printf("write succ! %d fileTrans=%d\n",writelength,fileTrans);
printf("write successful!\n");
//break;
                }

Int recvfrom( SOCKET s,char FAR *buf,int len,nt flags);不论是客户还是服务器应用程序都用recvfrom函数从另一端接收数据,根据返回值判断数据接收情况。s指定接收端套接字描述符;buf指明一个缓冲区,该缓冲区用来存放recvfrom函数接收到的数据;len指明buf的长度;flags一般为0;

客户端

创建套接字

int sockfd;

if((sockfd = socket(AF_INET,SOCK_DGRAM,0))<0)
{
    printf("socket build error!\n");
}
else
{
    printf("socket build success!\n");
}

向服务器发出连接请求

memset(&server,0,sizeof(server)); 
server.sin_family= AF_INET;
server.sin_port = htons(8888);
if(inet_pton(AF_INET,"127.0.0.1",&server.sin_addr)<0)
{
    printf("bind error!\n");
}
else
{
    printf("bind success!\n");
}

与服务器之间进行数据传输

lenpath = sendto(sockcd,filepath,strlen(filepath),0,(struct sockaddr *)&server,addrlen);// put file path to sever 
if(lenpath<0)
{
    printf("filepath send error!\n");
}
else
{
    printf("filepath send success!\n");
}
printf("begin send data...\n");
int data= 1;
while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf("data= %d   ",data);
data++;
    //printf("fileTrans =%d\n",fileTrans);
    if(sendto(sockcd,buffer,fileTrans,0,(struct sockaddr *)&server,addrlen)<0)
    {
        printf("send failed!\n");
        break;
    }
else{
printf("send successful!\n");
}

SendTo是一个计算机函数,指向一指定目的地发送数据,sendto()适用于发送未建立连接的UDP数据包 (参数为SOCK_DGRAM)。int sendto(SOCKET s, const char FAR *buf, int len, int flags);参数s为已连接的本地套接字描述符。buf指向存有发送数据的缓冲区的指针,其长度由len指定。flags指定传输控制方式,如是否发送带外数据等。 如果没有错误发生,send()返回总共发送的字节数。否则它返回SOCKET_ERROR

调试

使用visual studio code进行调试,安装c/c++扩展。 先运行服务器,后运行客户端;然后在服务器中输入拟发送的数据;

参考文献

何润岸. 基于UDP进行大规模数据传输的可靠传输系统的设计与实现[D]. 2015.

陈双全. 浅论C语言在提高程序执行效率上的编程技巧[J]. 信息技术与信息化, 2019(10).

云思雨. 议Linux系统下的计算机C语言编程技巧[J]. 环球市场信息导报, 2017, 000(047):121-121.

李芙蓉. 基于Winsock流套接字的进程通信的实现[J]. 西安文理学院学报(自然科学版), 2010, 13(002):81-84.

张恺. 基于UDP的可靠文件传输协议的设计与实现[D]. 西安电子科技大学, 2014.

# UDP协议
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录