• Linux网络编程(socket的udp通信)


    Linux网络编程(socket的udp通信)

    UDP是无连接的,即发送数据之前不需要建立连接,它尽最大努力交付,即不保证可靠交付,在一些要求实时性的通信中多有用到如游戏,视频等,UDP是面向报文的,有别于tcp的一对一通信,udp支持一对一、一对多、多对一和多对多的交互通信等。

    一、udp通信用到的相关函数解析

    int socket(int domain, int type, int protocol);
    功能:创建socket对象
    type:SOCK_DGRAM 数据报协议 UDP

    int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    功能:绑定socket和通信地址
    sockfd:socket描述符
    addr:地址结构体指针,实际传递的是 sockaddr_un或者sockaddr_in 结构体指针,需要把它们统一转换为sockaddr*类型。具体sockaddr_in结构体在socket的本地通信博文中有提到,这里不再赘述。

    UDP专属的数据发送接收函数
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
    功能:UDP协议发送数据
    sockfd:socket描述符
    buf:待发送数据内存首地址
    len:待发送数据的字节数
    flags:是否阻塞 一般写0阻塞即可
    dest_addr:通信目标的地址
    addrlen:地址结构体的字节数
    返回值:成功发送的字节数,0表示通信关闭,-1表示出现错误

    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
    功能:UDP协议接收数据
    sockfd:socket描述符
    buf:存储接收数据的缓冲区内存首地址
    len:缓冲区的字节数
    flags:是否阻塞 一般写0阻塞即可
    src_addr:用于存储发送者的地址
    addrlen:既是输入,也是输出,既告诉函数当前src_addr结构体的字节数,同时也能实际接收到发送者的地址结构体字节数。
    返回值:成功接收到的字节数,0表示通信关闭,-1表示出现错误。

    二、udp通信的编程模型

    基于UDP通信协议的网络通信编程模型:

       接收端                 发送端
    创建socket             创建socket
    准备通信地址            准备通信地址
    绑定                   ...
    接收请求                发送请求
    响应请求                接收响应
    关闭socket              关闭socket
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、dup通信编程示例

    服务器端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    typedef struct sockaddr* SP;
    
    int main(int argc,const char* argv[])
    {
    	//	创建socket
    	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    	if(0 > sockfd)
    	{
    		perror("socket");
    		return EXIT_FAILURE;
    	}
    	
    	//	准备本机通信地址
    	struct sockaddr_in srv_addr = {},cli_addr = {};
    	srv_addr.sin_family = AF_INET;
    	srv_addr.sin_port = htons(7788);
        //这里的“xxx.xx.xx.xx”写本机的ip地址,可以用ifconfig命令查看,windows可以用ipconfig查看
    	srv_addr.sin_addr.s_addr = inet_addr("xxx.xx.xx.xx");
    	socklen_t addrlen = sizeof(srv_addr);
    
    	//	绑定
    	if(bind(sockfd,(SP)&srv_addr,addrlen))
    	{
    		perror("bind");
    		return EXIT_FAILURE;
    	}
    
    	char buf[4096] = {};
    	size_t buf_size = sizeof(buf);
    
    	for(;;)
    	{
    		//	接收数据和对方的地址
    		int ret = recvfrom(sockfd,buf,buf_size,0,(SP)&cli_addr,&addrlen);
    		if(0 >= ret)
    		{
    			printf("网络异常,通信结束!");
    			close(sockfd);
    			return EXIT_FAILURE;
    		}
    		printf("from %s recv:[%s] bits:%d\n",
    			inet_ntoa(cli_addr.sin_addr),buf,ret);
    
    		//	返回响应
    		strcat(buf,"from udpS");
    		ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&cli_addr,addrlen);
    		if(0 >= ret)
    		{
    			printf("对方网络异常!\n");	
    		}
    	}
    }	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    客户端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    typedef struct sockaddr* SP;
    
    int main(int argc,const char* argv[])
    {
    	//	创建socket
    	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    	if(0 > sockfd)
    	{
    		perror("socket");
    		return EXIT_FAILURE;
    	}
    	
    	//	准备服务器通信地址
    	struct sockaddr_in srv_addr = {};
    	srv_addr.sin_family = AF_INET;
    	srv_addr.sin_port = htons(7788);
    	srv_addr.sin_addr.s_addr = inet_addr("xx.xx.xxx.xxx");//这里写需要通信的ip地址
    	socklen_t addrlen = sizeof(srv_addr);
    
    	char buf[4096] = {};
    	size_t buf_size = sizeof(buf);
    
    	for(;;)
    	{
    		printf(">>>");
    		scanf("%s",buf);
    		if(0 == strcmp(buf,"quit"))
    		{
    			printf("结束通信!\n");
    			close(sockfd);
    			return EXIT_SUCCESS;
    		}
    		int ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&srv_addr,addrlen);
    		if(0 >= ret)
    		{
    			printf("网络异常!\n");
    			close(sockfd);
    			return EXIT_FAILURE;
    		}
    		//	接收数据和对方的地址
    		ret = recvfrom(sockfd,buf,buf_size,0,(SP)&srv_addr,&addrlen);
    		if(0 >= ret)
    		{
    			printf("网络异常,通信结束!");
    			close(sockfd);
    			return EXIT_FAILURE;
    		}
    		printf("from %s recv:[%s] bits:%d\n",
    			inet_ntoa(srv_addr.sin_addr),buf,ret);
    
    	}
    }	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
  • 相关阅读:
    微信小程序 | 基于云数据库的许愿墙
    数据处理任务——知识点总结
    国产办公软件崛起,WPS发布新版本,金山系兄弟软件来助力
    在Linux中安装中文包
    如何压缩jpg图片的大小?可以一键压缩图片的软件有哪些?
    己知一棵有 2011 个结点的树,其叶结点个数为 116,该树对应的二叉树无右孩子的结点个数是
    1.3 常规信息系统集成技术
    OSI与TCP/IP 5层协议
    神经网络量化----为了部署而特别设计
    ViT-YOLO论文解读
  • 原文地址:https://blog.csdn.net/m0_50711528/article/details/126771271