您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

UDP实现客户端通信(简单易懂)

时间:2021-06-07 13:45:33  来源:  作者:乐天派程序员

在写面向UDP连接的 socket 的通信程序时,我先总结归纳一些关于面向TCP和UDP连接的socket 通信程序的相关知识:

面向TCP连接的 socket 通信程序:

服务端:创建套接字,指定协议族(sockaddr_in),绑定,监听,接受连接,发送或接受数据,关闭连接;

客户端:创建套接字,指定协议族,连接(connect),发送或接受数据,关闭连接;

TCP在接受数据时:write/send/sendto, read/recv/recvfrom都可以用, 通常会用send, recv;

但在面向UDP的socket程序中,发送数据时用sendto的话,就不用connect了,但是在面向TCP的程序中,在发送数据时,即使用sendto,也必须用connect

面向UDP连接的socket通信程序:

服务端:创建套接字,指定协议族(sockaddr_in),绑定(不需要listen和accept),发送或接收数据;

客户端:创建套接字,指定协议族,连接(和TCP的客户端步骤一样),发送或接受数据;

UDP常用sendto,recvfrom; 注意:用sendto时,就不用connect了(用了也没事),其他的(write, send)

必须用connect;

补充:1、无论是TCP还是UDP,默认情况下创建的都是阻塞模式的套接字,执行到(accept,connect, write/send/sento,read/recv/recvfrom)等语句时,会一直等待(connect)有点列外,它连接一段时间,如果连接不成功,会以错误形式返回,不会一直等待

2、可以把socket设置成非阻塞模式, linux下用fcntl函数,TCP和UDP设置成非阻塞模式以后,效果是一样的,都不再等待而是立即返回

3、TCP面向连接, UDP面向无连接

TCP:客户端退出程序时或断开连接时,TCP的这个函数会立即返回不在阻塞(因为服务端自己知道客户端已经退出或断开连接,证明它是面向连接的)

UDP:始终保持阻塞(服务端不知道客户端已经退出或断开连接,证明它是面向无连接的)

4、TCP无边界,UDP有边界

TCP:客户端连续发送数据,只要服务端的这个函数的缓冲区足够大,会一次性接收过来

(客户端是分好几次发过来,是有边界的,而服务端却一次性接收过来,所以证明是无边界的)

UDP:客户端连续发送数据,即使服务端的这个函数的缓冲区足够大,也只会一次一次的接收,客户端分几次发送过来,服务端就必须按几次接收

补充:

1、socket()的参数不同

2、UDP Server不需要调用listen和accept

3、UDP收发数据用sendto/recvfrom函数

4、UDP:shutdown函数无效

5、TCP:地址信息在connect/accept时确定 UDP:在sendto/recvfrom函数中每次均需指定地址信息Sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器进行连接,所以在发送数据时应指明目的地址

下面就是我写的利用UDP连接和多线程实现的客户端之间的通信代码:

服务器端:UdpServer.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
 
#define PORT 8888
 
struct info
{
	char buf[100];
	int port;
};
 
int main()
{
	int sockfd, length, ret, j, i = 0;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr[10] = {0};
	struct sockaddr_in tmp_addr;
	struct info RecvBuf = {0};
 
	sockfd = socket(PF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
	{
		perror("socket");
		exit(1);
	}
 
	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = PORT;
	server_addr.sin_addr.s_addr = inet_addr("192.168.0.128");
 
	ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (ret < 0)
	{
		perror("bind");
		exit(1);
	}
	while (1)
	{
		length = sizeof(client_addr[0]);
		ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&tmp_addr, &length);
		if (ret < 0)
		{
			perror("recvfrom");
			exit(1);
		}
		printf("Recv From Client %d : %sn", tmp_addr.sin_port, RecvBuf.buf);
		if (0 == i)
		{
			client_addr[0].sin_family = tmp_addr.sin_family;
			client_addr[0].sin_port = tmp_addr.sin_port;
			client_addr[0].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
			i++;
		}
		else
		{
			for (j = 0; j < i; j++)
			{
				if (tmp_addr.sin_port == client_addr[j].sin_port)
				{
					break;
				}
				if (j == i - 1)
				{
					client_addr[i].sin_family = tmp_addr.sin_family;
			    	        client_addr[i].sin_port = tmp_addr.sin_port;
					client_addr[i].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
					i++;
				}
			}
		}
		if (!strcmp(RecvBuf.buf, "bye"))
		{
			break;
		}
		strcat(RecvBuf.buf, "-server");
		for(j = 0; j < i; j++)
		{
			if (RecvBuf.port == client_addr[j].sin_port)
			{
				break;
			}
			if (j == i - 1)
			{
				break;
			}
		}
	
		ret = sendto(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&client_addr[j], sizeof(client_addr[0]));
		if (ret < 0)
		{
			perror("sendto");
			exit(1);
		}
		memset(&RecvBuf, 0, sizeof(RecvBuf));
	}
	close(sockfd);
	return 0;
}

客户端:UdpClient.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define PORT  8888
 
struct info
{
	char buf[100];
	int port;
};
 
void *Send(void *arg)
{
	struct info SendBuf = {0};
	struct sockaddr_in server_addr;
	int ret;
 
	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = PF_INET;
	server_addr.sin_port = PORT;
	server_addr.sin_addr.s_addr = inet_addr("192.168.0.128");
 
	while(1)
	{
		scanf("%s %d", SendBuf.buf, &SendBuf.port);
 
		ret = sendto(*(int *)arg, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
		if (ret < 0)
		{
			perror("sendto");
			exit(1);
		}
		if (!strcmp(SendBuf.buf, "bye"))
		{
			break;
		}
		bzero(&SendBuf, sizeof(SendBuf));
	}
}
void *Recv(void *arg)
{
	struct info RecvBuf = {0};
	int length;
	struct sockaddr_in server_addr;
	int ret;
	while (1)
	{
		length = sizeof(server_addr);
		ret = recvfrom(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);
		if (ret < 0)
		{
			perror("recvfrom");
			exit(1);
		}
		printf("Recv From Server : %sn", RecvBuf.buf);
	}
}
int main()
{
	int sockfd, ret, length;
	struct info SendBuf = {0};
	pthread_t tid[2];
	sockfd = socket(PF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
	{
		perror("sockt");
		exit(1);
	}
	ret = pthread_create(&tid[0], NULL, Send, (void *)&sockfd);
	if (ret < 0)
	{
		perror("pthread_create");
		exit(1);
	}
	ret = pthread_create(&tid[1], NULL, Recv, (void *)&sockfd);
	if (ret < 0)
	{
		perror("pthread_create");
		exit(1);
	}
	
	pthread_join(tid[0], NULL);
	pthread_join(tid[1], NULL);
	close(sockfd);
	return 0;
}


Tags:UDP   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
简介简单就是美。在网络协议的世界中,TCP和UDP是建立在IP协议基础上的两个非常通用的协议。我们现在经常使用的HTTP协议就是建立在TCP协议的基础上的。相当于TCP的稳定性来说...【详细内容】
2021-12-06  Tags: UDP  点击:(21)  评论:(0)  加入收藏
一、TCP协议位于传输层, 提供可靠的字节流服务。所谓的字节流服务(Byte Stream Service) 是指, 为了方便传输, 将大块数据分割成以报文段(segment) 为单位的数据包进行管理。 而可...【详细内容】
2021-11-26  Tags: UDP  点击:(34)  评论:(0)  加入收藏
作者 | Vitaly Suturikhin翻译 | 徐鋆 低广播延迟已经成为任何关于建设源端站和CDN的招标和竞争中的必要特性。以前这种标准只适用于体育广播,但现在运营商要求每个领域的广...【详细内容】
2021-08-17  Tags: UDP  点击:(70)  评论:(0)  加入收藏
在写面向UDP连接的 socket 的通信程序时,我先总结归纳一些关于面向TCP和UDP连接的socket 通信程序的相关知识:面向TCP连接的 socket 通信程序:服务端:创建套接字,指定协议族(sock...【详细内容】
2021-06-07  Tags: UDP  点击:(163)  评论:(0)  加入收藏
UDP报文接收概述UDP数据报的接收要分两部分来看: 网络层接收完数据包后递交给UDP后,UDP的处理过程。该过程UDP需要做的工作就是接收数据包并对其进行校验,校验成功后将其放入接...【详细内容】
2021-06-04  Tags: UDP  点击:(93)  评论:(0)  加入收藏
一、引言UDP是TCP/IP协议中的传输层协议的一种,本文介绍了在Linux下编写基于UDP协议的Client/Server模型的程序的方法,并给出了一个echo Client/Server例子程序。二、UDP协议...【详细内容】
2021-05-13  Tags: UDP  点击:(274)  评论:(0)  加入收藏
UDP协议是英文UserDatagramProtocol的缩写,即用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络...【详细内容】
2021-05-12  Tags: UDP  点击:(179)  评论:(0)  加入收藏
作者:Draven 面向信仰编程为什么这么设计(Why&rsquo;s THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同...【详细内容】
2021-04-13  Tags: UDP  点击:(234)  评论:(0)  加入收藏
对于TCP端口是否开放,测试的方式很简单,Windows系统cmd命令行下使用telnet就可以进行探测 那么如何探测UDP端口是否开放?下面介绍Linux和windows下探测UDP 端口是否开放的几种...【详细内容】
2021-03-08  Tags: UDP  点击:(485)  评论:(0)  加入收藏
再谈会话现在IP网络里面离不开TCP、UDP这两种传输层协议,主流应用都基于这两种协议来做封装传输,对于TCP来说,在发送实际数据的时候必须先建立可靠的连接,俗称 ”三次握手”,而UD...【详细内容】
2021-03-04  Tags: UDP  点击:(667)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条