当前位置: 首页 > article >正文

Linux网络编程6——UDP通信

一.UDP通信

1.TCP通信和UDP通信各自的优缺点

TCP:	面向连接的,可靠数据包传输。对于不稳定的网络层,采取完全弥补的通信方式。 丢包重传。

​	优点:
​		稳定。		
​			数据流量稳定、速度稳定、顺序
​	缺点:
​		传输速度慢。相率低。开销大。

​	使用场景:数据的完整型要求较高,不追求效率。

​		  大数据传输、文件传输。

UDP:	无连接的,不可靠的数据报传递。对于不稳定的网络层,采取完全不弥补的通信方式。 默认还原网络状况

​	优点:

​		传输速度块。相率高。开销小。

​	缺点:
​		不稳定。
​			数据流量。速度。顺序。

​	使用场景:对时效性要求较高场合。稳定性其次。

​		  游戏、视频会议、视频电话。		腾讯、华为、阿里  ---  应用层数据校验协议,弥补udp的不足。

2.UDP实现的 C/S 模型

  • recv()/send() 只能用于 TCP 通信。 替代 read、write

  • accpet(); ---- Connect(); —被舍弃

server

	lfd = socket(AF_INET, STREAM, 0);	SOCK_DGRAM --- 报式协议。

	bind();

	listen();  --- 可有可无

	while(1){

		read(cfd, buf, sizeof) --- 被替换 --- recvfrom() --- 涵盖accept传出地址结构。

			ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

				sockfd: 套接字

				buf:缓冲区地址

				len:缓冲区大小

				flags: 0

				src_addr:(struct sockaddr *)&addr 传出。 对端地址结构

				addrlen:传入传出。

			返回值: 成功接收数据字节数。 失败:-1 errn。 0: 对端关闭。

		小-- 大
			
		write();--- 被替换 --- sendto()---- connect

			 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

				sockfd: 套接字

				buf:存储数据的缓冲区

				len:数据长度

				flags: 0

				src_addr:(struct sockaddr *)&addr 传入。 目标地址结构

				addrlen:地址结构长度。

			返回值:成功写出数据字节数。 失败 -1, errno		
	}

	close();

client

	connfd = socket(AF_INET, SOCK_DGRAM, 0);

​	sendto(‘服务器的地址结构’, 地址结构大小)

​	recvfrom()

​	写到屏幕

​	close();

3.代码

server.cpp:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_PORT 9527

int main()
{
    int sockfd;
    sockfd = socket(AF_INET,SOCK_DGRAM,0);             //表示选择UDP协议

    char buf[1024],clie_IP[BUFSIZ];
    int ret;

    struct sockaddr_in serv_addr,clie_addr;
    socklen_t clie_addr_len = sizeof(clie_addr);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd,(struct soakaddr *)&serv_addr,sizeof(serv_addr));     //绑定服务器的信息

    while(1)
    {
        ret =n recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&clie_addr,&clie_addr_len);

        printf("client 's IP:%s   port:%d\n", 
                inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,clie_IP,sizeof(clie_IP)),
                ntohs(clie_addr.sin_port));

        for(int i = 0;i<ret;i++)
            buf[i] = toupper(buf[i]);

        sendto(socket,buf,ret,0,(struct sockaddr *)*clie_addr,clie_addr_len);
    }

    close(sockfd);
}

cilent.cpp:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    int sockfd, n;
    char buf[BUFSIZ];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (fgets(buf, BUFSIZ, stdin) != NULL) {
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (n == -1)
            perror("sendto error");

        n = recvfrom(sockfd, buf, BUFSIZ, 0, NULL, 0);         //NULL:不关心对端信息
        if (n == -1)
            perror("recvfrom error");

        write(STDOUT_FILENO, buf, n);
    }

    close(sockfd);

    return 0;
}

二.本地套接字

1.回顾/了解

进程间通信:

  • pipe管道:应用性最强
  • FIFO有名管道:可以在没有血缘关系间进行通信
  • mmap共享内存:没有血缘关系间通信且可以返回读取
  • 信号:开销最小
  • 本地套接字(domain):稳定性最好

对比网络编程的TCP的C/S模型,注意以下几点:

函数原型:

#include <sys/socket.h>

int socket(int domain, int type, int protocol);
  • domain:用来指定传输协议,网络套接字使用AF_INETAF_INET6分别表示IPv4和IPv6,而本地套接字需要使用AF_UNIXAF_LOCAL
  • type:用来指定协议类型,可以取SOCK_STREAM表示流式协议或SOCK_DGRAM表示报式协议
  • protocol:传0表示默认协议

type为SOCK_STREAM且protocol=0表示使用TCP传输,type为SOCK_DGRAM且protocol=0表示使用UDP传输。


第二步,注意bind函数的地质结构体发生变化,由原来的sockaddr_in变成了sockaddr_un

struct sockaddr_in {
__kernel_sa_family_t sin_family; 			/* Address family */  	地址结构类型
__be16 sin_port;					 	/* Port number */		端口号
struct in_addr sin_addr;					/* Internet address */	IP地址
};
struct sockaddr_un {
__kernel_sa_family_t sun_family; 		/* AF_UNIX */			地址结构类型
char sun_path[UNIX_PATH_MAX]; 		/* pathname */		socket文件名(含路径)
};

变化代码

2. 地址结构:  sockaddr_in --> sockaddr_un

		struct sockaddr_in srv_addr; --> struct sockaddr_un srv_adrr;

		srv_addr.sin_family = AF_INET;  --> srv_addr.sun_family = AF_UNIX;
·
		srv_addr.sin_port = htons(8888);    strcpy(srv_addr.sun_path, "srv.socket")

		srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);			len = offsetof(struct sockaddr_un, sun_path) + strlen("srv.socket");
	
		bind(fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));  --> 	bind(fd, (struct sockaddr *)&srv_addr, len); 
  1. bind()函数调用成功,会创建一个 socket。因此为保证bind成功,通常我们在 bind之前, 可以使用 unlink(“srv.socket”);
4. 客户端不能依赖 “隐式绑定”。并且应该在通信建立过程中,创建且初始化2个地址结构:

	1) client_addr --> bind()

	2)  server_addr --> connect();

http://www.kler.cn/a/539773.html

相关文章:

  • 机器学习笔记
  • 深度学习|表示学习|Instance Normalization 全面总结|26
  • PHP 运算符
  • sqlite 查看表结构
  • [LUA ERROR] bad light userdata pointer
  • 轻松理解CSS中的float浮动元素
  • 深入解析 Sojson.v6 混淆加密机制
  • ArcGIS实现提取处于某一属性下栅格tif中的建筑物shp
  • 机器学习-智能写作助手
  • 软件工程-软件需求分析基础
  • 12.15 实战 ReAct:SerpAPI + LLM-MATH 构建自主解题智能体
  • 快速搭建 Elasticsearch 8 集群:零基础实战与升级注意事项
  • Java面试题-Redis缓存
  • GrassWebProxy
  • MySQL索引深度解析:从原理到优化
  • 大语言模型RAG,transformer和mamba
  • go语言中的反射
  • JavaScript系列(64)--响应式状态管理实现详解
  • webpack系统学习
  • RK3568使用C++和FFmpeg进行视频流,并使用自带GPU加速
  • 寒假2.7
  • Springboot原理(面试高频)
  • Linux | 自动化构建 —— make / Makefile
  • 导航守卫router.beforeEach
  • 设计模式.
  • F#语言的物联网