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

Linux Day18 TCP_UDP协议及相关知识

一、网络基础概念

1.1 网络

网络是由若干结点和连接这些结点的链路组成,网络中的结点可以是计算机,交换机、

路由器等设备。

1.2 互联网

把多个网络连接起来就构成了互联网。目前最大的互联网就是因特网。

网络设备有:交换机、路由器、集线器

传输介质有:双绞线、同轴电缆、光纤,无线

00530813c3d64ef5a92822bd3ceacfae.png8266b7137811410998c777e59b748f9a.gif

1.3 IP地址

IP 地址就是给因特网上的每一个主机(或路由器)的每一个接口分配的一个在全世界

范围内唯一的标识符。IP 地址因其特殊的结构使我们可以在因特网上很方便地进行寻址。

IP 地址有分 IPV4 和 IPV6 两种类别格式,IPV4 是类似”A.B.C.D”的格式,它是 32 位的,用“.”分成四个段,每个段是 8 个位(值为 0-255),用 10 进制表示。IPV6 地址是 128 位,格式类似”XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX”,用“:“分成 8 个段,每个段 16 个位,用 4 个 16 进制数表示。

接下来描述的 IP 地址默认都指的是 IPV4 的地址。为了便于寻址,了解目标主机的位置,每个 IP 地址由网络号和主机号两个部分构成。同一个物理网络上所有的主机都使用同 一个网络号,只是主机号不同

1.4 inet_addr()

计算机使用的是无符号整型,而用户熟悉的是点分十进制的字符串。

该函数可以将点分十进制字符串表示的ipv4地址转化为用网络字节序整数表示的ipv4.即无符号整型

1.5 查看ip地址方法

1、Windows

win+r --->cmd-->ipconfig

f93a7b326a984b978c3c0ed4bdb7e210.png6da50f2572344364a15c84e5c8b536a1.gif

2、Linux

ifconfig

1.6 端口号

应用程序的代号,进程号是会变的,但是端口号不会变。所以我们使用端口号去唯一标识应用程序的。

1.7 127.0.0.1

127.0.0.1是回送地址,指本地机,一般用来测试使用。回送地址(127.x.x.x)是本机回送地址(Loopback Address),即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输。

通信需要:源ip+端口 目的ip+端口

1.8 协议

网络协议就是一组网络规则的集合,是我们共同遵守的约定或标准。常见的协议:

◼ HTTP:超文本传输协议

◼ FTP: 文件传输协议

◼ TELNET : 是 internet 远程登陆服务的标准协议。

◼ TCP : 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可

靠的、基于字节流的传输层通信协议

◼ UDP :用户数据报协议

◼ IP : Internet Protocol 简称 IP,又译为网际协议或互联网协议

◼ ICMP :因特网控制报文协议

◼ ARP : 地址解析协议,是根据 IP 地址获取 MAC 地址的协议

◼ RARP : 逆地址解析协议

TCP报头

d82d8e3d4206482d96661a5c723206e3.png

这里的ACK,FIN,SYN后面介绍

1.9 服务器端编写

1.9.0 OSI 的 7 层模型与 tcp/ip 协议族体系 4 层结构**

1.9.0.1 OSI/ISO模型

应用层

表示层

会话层

传输层 加TCP/IP协议

网络层 加IP协议

数据链路层 加帧

物理层

1.9.0.2 TCP/IP模型

应用层

表示层

网络层

网际接口层(数据链路层+物理层)

tcp的通信流程80d8fbb4c2044513b03cc430b5a396b7.png

1.9.1 创建套接字

 

int socket(int domain, int type, int protocol)

有了套接字就可以通过网络进行数据的收发

socket()创建套接字,成功返回套接字的文件描述符,失败返回-1

domain: 设置套接字的协议族, AF_INET(IPv4)和 AF_INET6(IPv6)

type: 设置套接字的服务类型 SOCK_STREAM(流服务,用于TCP协议)和SOCK_DGRAM(数据报,用于UDP协议)

注意 PF开头的是协议族,AF开头的是地址族,在Windows上没有任何区别,在Linux上差别不大

4a0cbf9c0be545af8cdae097df07e015.png

protocol: 一般设置为 0,表示使用默认协议

1.9.2 命名socket

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

用来指定套接字使用的IP地址和端口。

bind()将 sockfd 与一个 socket 地址绑定,成功返回 0,失败返回-1

sockfd 是网络套接字描述符,即socket()的返回值。

addr 是地址结构,是一个结构体。

addrlen 是 socket 地址的长度。

 

专用 socket 地址结构

TCP/IP 协议族有 sockaddr_in 和 sockaddr_in6 两个专用 socket 地址结构体,它们分

别用于 IPV4 和 IPV6:

sin_family: 地址族 AF_INET

sin_port: 端口号,需要用网络字节序表示,在这里我们要注意大小端问题,在不同的操作系统上,大小端是不一样的,为了方便我们的服务器端,我们可以使用htons()函数将所有端口的字节序统一好。

sin_addr: IPV4 地址结构:s_addr 以网络字节序表示 IPV4 地址

 

struct sockaddr_in

{

sa_family_t sin_family;

u_int16_t sin_port;

struct in_addr sin_addr;

};

1.9.3 监听socket

socket被命名后,还不能马上接受客户连接,我们需要使用如下系统调用创建一个监听队列以存放待处理的客户连接。

int listen(int sockfd, int backlog);

listen()创建一个监听队列以存储待处理的客户连接,成功返回 0,失败返回-1

sockfd 是被监听的 socket 套接字

backlog 表示处于完全连接状态的 socket 的上限,典型值为5

1.9.4 接受连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept()从 listen 监听队列中接收一个连接,成功返回一个新的连接 socket,

该 socket 唯一地标识了被接收的这个连接,失败返回-1

sockfd 是执行过 listen 系统调用的监听 socket

addr 参数用来获取被接受连接的远端 socket 地址,一般是客户端

addrlen 指定该 socket 地址的长度

注意:accept返回值为0表明我们的客户端结束标准输入,这时我们接受到的值就为0.

1.9.5 TCP数据读写

ssize_t recv(int sockfd, void *buff, size_t len, int flags);

ssize_t send(int sockfd, const void *buff, size_t len, int flags);

recv()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小

send()往 socket 上写入数据,buff 和 len 参数分别指定写缓冲区的位置和数据长度

flags 参数为数据收发提供了额外的控制,一般为0

1.9.6 关闭连接

关闭该连接对应的socket

int close(int sockfd);

close()关闭一个连接,实际上就是关闭该连接对应的 socket

1.10 客户端编写

1.10.1 创建套接字 socket()

与服务器端一样

1.10.2 发起连接

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

connect()客户端需要通过此系统调用来主动与服务器建立连接,

成功返回 0,失败返回-1

sockfd 参数是由 socket()返回的一个 socket。

serv_addr 是服务器监听的 socket 地址

addrlen 则指定这个地址的长度

1.10.3 发送数据 send()

与服务器端一样

1.10.4 接受数据 recv()

与服务器端一样

1.10.5 结束连接 close()

与服务器端一样

综上所述,TCP协议的基本流程就是如下图所示

a85df326e56d4441ad61cdaf8c530707.png

1.11 编写代码

1.0版本 只能进行一次通信

1.11.1 编写服务端(1.0)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){exit(1);}struct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//当前主机的ip地址,通过ifconfig获取int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("bind err\n");exit(0);}res=listen(sockfd,5);if(res<0){printf("listen err\n");exit(0);}while(1){int len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);if(c<0){continue;}printf("accept c=%d\n",c);char buff[128]={0};int n=recv(c,buff,strlen(buff)-1,0);printf("n=%d\n",n);printf("buff=%s\n",buff);send(c,"ok",2,0);close(c);}
​
}

 

1.11.2 编写客户端(1.0)

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){printf("socket err\n");exit(1);}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//注意服务器和客户端必须要连接在同一个网络下int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("connect err\n");exit(0);}   printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("recv:%s\n",buff);close(sockfd);
}

结果

1c941607ee2844389422b3b12fd8265a.png

服务器端可以accept到客户端发送来的数据

客户端可以将服务器端接收到数据后返回的信息接受

二、 TCP 协议特点

2.1 连接的建立与断开

TCP 协议提供的是:面向连接、可靠的、字节流服务。

使用 TCP 协议通信的双发必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP 连接是全双工的,双方的数据可以通过一个连接进行读写。完成数据交换之后,通信双方都必须断开连接以释放系统资源。

TCP 的服务器端和客户端编程流程如下:

ece62a83d15e478392d5fa41ffa79c95.png

socket()方法是用来创建一个套接字,有了套接字就可以通过网络进行数据的收发。

bind()方法是用来指定套接字使用的 IP 地址和端口。

listen()方法是用来创建监听队列。监听队列有两种,一个是存放未完成三次握手的连接,一种是存放已完成三次握手的连接。listen()第二个参数就是指定已完成三次握手队列的长度。

accept()处理存放在 listen 创建的已完成三次握手的队列中的连接。每处理一个连接,则accept()返回该连接对应的套接字描述符。如果该队列为空,则 accept 阻塞。

connect()方法一般由客户端程序执行,需要指定连接的服务器端的 IP 地址和端口。该方法执行后,会进行三次握手, 建立连接。

send()方法用来向 TCP 连接的对端发送数据。send()执行成功,只能说明将数据成功写入到发送端的发送缓冲区中,并不能说明数据已经发送到了对端。send()的返回值为实际写入到发送缓冲区中的数据长度。

recv()方法用来接收 TCP 连接的对端发送来的数据。recv()从本端的接收缓冲区中读取数据,如果接收缓冲区中没有数据,则 recv()方法会阻塞。返回值是实际读到的字节数,如果recv()返回值为 0, 说明对方已经关闭了 TCP 连接。

close()方法用来关闭 TCP 连接。此时,会进行四次挥手

2.2 TCP 固定报头

TCP报头267366871c0042688e2ac9d85de44b62.png

ACK:表示确认号是否有效,我们称携带ACK标志的TCP的报文段为确认报文段。

SYN:表示请求建立一个连接,我们称携带SYN标志的TCP的报文段为同步报文段。

FIN:表示通知对方本端要关闭连接了,我们称携带FIN标志的TCP的报文段为结束报文段。

seq(Sequence Number):表示这个tcp包的序列号。

2.3 三次握手

(1)第一次握手,主机A向主机B发出请求数据包:“我想给你发数据,可以吗?”这是第一次对话。

(2)第二次握手,主机B向主机A发送同意连接,并要求同步的数据包(同步就是两台主机协调工作,一台在发送,一台在接收):“可以,你什么时候发?”这是第二次对话。

(3)第三次握手,主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接收吧!”这是第三次对话。

握手发生在connet()的操作下。883dd0247fb7444aa0b4797a1be6d292.png

主机A向主机B发送请求数据包,这是第一次对话,S表示SYN,即请求建立一个连接

主机B向主机A 发送同意连接(回应 ACK,确认该序列号有效),并要求同步数据包(SYN),所以有seq和ACK

主机A向主机B 发送一个数据包确认主机B的要求同步。ACK表示确认该序列号有效7578544f50ef49798bae57b50ce1ec2b.png

 

2.4 中间传输信息9b426271e3424137a81429b0b636831e.png

A主机给B主机发送了一个长度为3的字符串

B主机给A主机发送了一个长度为2的字符串,表明他收到该信息

A主机给B主机发送了确认收到的,即ack

 

2.5 四次挥手

断开连接

四次挥手:

9ce7bdccd8a840648701e439df57307b.png

d0f98f5da01f455e930bda70a39a389e.png

三次挥手:客户端和服务器端关闭相差不大,这个时候就只有三次即中间的ACK和FIN合并在一起。08ce417ae18e4b19b22d70e337147f9f.png

2.6 服务器端 (2.0)

服务器端和客户端可以进行多次交互,直到客户端结束连接

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1){exit(1);}struct sockaddr_in saddr, caddr;memset(&saddr, 0, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));if (res == -1){printf("bind err\n");exit(0);}res = listen(sockfd, 5);if (res < 0){printf("listen err\n");exit(0);}while (1){int len = sizeof(caddr);int c = accept(sockfd, (struct sockaddr *)&caddr, &len);if (c < 0){continue;}while (1){printf("accept c=%d\n", c);char buff[128] = {0};int n = recv(c, buff, 127, 0);if (n <= 0)//recv返回值n==0表明客户端已经关闭连接了。{break;}printf("n=%d\n", n);printf("buff=%s\n", buff);send(c, "ok", 2, 0);}sleep(2);close(c);}
}

如果将recv接受数据能力改成每次收取1个,即int n = recv(c, buff, 1, 0);

2.6.1 缓冲区

12b81e0ab3954c48b402b3830ca7fbe4.png

如果recv能力改成1,那么每次只能从缓冲区中读取一个字符,直到接收缓冲区中没有数据,然后才会阻塞

8f8c19d512be4f79bee0a21761fa66f7.png

2.6.2 查看缓冲区

netstat -natp

Recv-Q :接收缓冲区

Send-Q:发送缓冲区

ESTABLLTSHED:已完成三次握手

bbb6ed73f93147e38bfac4c645da63fe.png

此时有2个ok在接收缓冲区,在下一次输出

2.6.3 流失服务特点

5c135299caf541398816c87e68024dd7.png不管中间如何分割,但是最后从发送端到接收端得到的结果是一致的

可靠性:

1:应答确认,超时重传机制

2:去重(报文有序号,有相同序号会丢失重复的),乱序重排(报文有序号)

2.6.4 粘包

粘包发生在发送或接收缓冲区中;应用程序从缓冲区中取数据是整个缓冲区中有多少取多少;那么就有可能第一个数据的尾部和第二个数据的头部同时存在缓冲区,而TCP是流式的,数据无边界,这时发生粘包。

 

4c086824587fd897a5954679fde3e9c0.jpeg

a1a9887df7ca442fb50eb9245dd34c14.png

客户端发了三次数据,服务器端一次接受完,客户端在Recv()处等待服务器回应收到,处于阻塞状态,而服务器端处于第二次recv()所以阻塞,这时这个粘包就会出现问题。解决方法就是在头部加上标识信息。

2.6.5 流量控制

TCP 协议是利用滑动窗口实现流量控制的。一般来说,我们总是希望数据传输得更快一些,不会一次只发一个字节。但是如果发送方把数据发得过快,接受方就可能来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。

在 TCP 的报头中有一个字段叫做接收通告窗口,这个字段由接收端填充,是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。所以发送端就会有一个发送窗口,这个发送窗口的大小是由接收端填充的接收通告窗口的大小决定的,并且窗口的位置会随着发送端数据的发送和接收到接收端对数据的确认而不断的向右滑动,将之称为滑动窗口。发送方的滑动窗口示意图如下:

f88505d487d84246a6c463a79fc611fc.png

2.7 客户端 (2.0)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){printf("socket err\n");exit(1);}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr= inet_addr("127.0.0.1");int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("connect err\n");exit(0);}   while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("recv:%s\n",buff);}close(sockfd);
}

02f2e5d6d4df4c098d1c90696ba7cc92.png

2.8 多线程,多进程并发

之前的代码存在一个问题:当一个客户端与服务器建立连接以后,服务器端 accept()返回,进而准备循环接收客户端发过来的数据。如果客户端暂时没发数据,服务端会在第 40 行的 recv()阻塞。此时,其他客户端向服务器发起连接后,由于服务器阻塞了,无法执行 accept()接受连接,也就是其他客户端发送的数据,服务器无法读取。服务器也就无法并发同时处理多个客户端。

目的:一个服务器能够同时收到多个客户端的数据

多线程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
​
void * fun(void* arg)
{int *p = (int*)arg;int c = *p;free(p);while( 1 ){char buff[128] = {0};int n = recv(c,buff,1,0);if ( n <= 0)// recv返回值n == 0 说明客户但关闭连接了{break;}
​printf("recv=%s\n",buff);send(c,"ok",2,0);}
​close(c);//关闭连接  挥手printf("client close\n");
}
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);//套接字 文件描述符if ( sockfd == -1 ){exit(1);}
​struct sockaddr_in saddr,caddr;//套接字地址 ip port memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("192.168.84.248");
​int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if ( res == -1 ){printf("bind err\n");exit(1);}
​res = listen(sockfd,5);if ( res == -1 ){exit(1);}
​while( 1 ){int c = accept(sockfd,NULL,NULL);if ( c < 0 ){continue;}
​printf("accept c=%d\n",c);
​pthread_t id;int * p = (int*)malloc(sizeof(c));*p = c;pthread_create(&id,NULL,fun,(void*)p);}
​
}

多进程

使用fork(),父子进程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
​
​
void fun(int c)
{while( 1 ){char buff[128] = {0};int n = recv(c,buff,127,0);if ( n <= 0)// recv返回值n == 0 说明客户但关闭连接了{break;}
​printf("recv=%s\n",buff);send(c,"ok",2,0);}
​close(c);//关闭连接  挥手printf("client close\n");
}
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);//套接字 文件描述符if ( sockfd == -1 ){exit(1);}
​struct sockaddr_in saddr,caddr;//套接字地址 ip port memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("192.168.84.248");
​int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if ( res == -1 ){printf("bind err\n");exit(1);}
​res = listen(sockfd,5);if ( res == -1 ){exit(1);}
​while( 1 ){int c = accept(sockfd,NULL,NULL);if ( c < 0 ){continue;}
​printf("accept c=%d\n",c);
​pid_t pid=fork();if(pid<0){printf("fork err\n");close(c);continue;}if(pid==0){close(sockfd);fun(c);exit(0);}}
​
}

2.9 抓包

使用命令

netstat -natp

三次握手时:

7d55ca0c038c498a9d82fceb26144c5b.png

四次挥手时:

ecc2b62f900c45689b18b290107a6e0e.png因为时间原因没有截到 TIME_WAIT

e0b5dd44caa7469d83c274631ccdbe7f.png三、 UDP 协议特点

UDP 数据报服务特点:发送端应用程序每执行一次写操作,UDP 模块就将其封装成一个 UDP 数据报发送。接收端必须及时针对每一个 UDP 数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取 UDP 数据,则 UDP 数据将被截断。

50008ee78b594a68a89fc710deb95b23.png与TCP不同的是UDP接收到的数据报会直接发给接收端,不会存在缓存区。

(1)UDP是一个非连接的协议,传输数据之前,源端和终端不建立连接,当它想传送时,就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。

在发送端,UDP传送数据的速度仅受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

(2)由于传输数据不建立连接,因此不需要维护连接状态,包括收发状态等。一台服务机可同时向多个客户机传输相同的消息。

(3)UDP信息包的包头很短,只有8字节,相对于TCP的20字节包头信息,UDP的包头开销很小。

(4)吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。

(5)UDP会尽最大努力去传输和接受数据且没有限制,但并不保证可靠的数据交付,主机也不需要维持复杂的链接状态表(里面有许多参数)。

(6)UDP是面向报文的。发送方的UDP对应用程序传过来的报文,在添加包头后就向下交付给IP层。既不拆分,也不合并,而只是保留这些报文的边界,因此,应用程序需要自己限制合适的报文大小,以免报文太大导致丢失率高。

3.1 API

UDP 数据读写:

recvfrom()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大

src_addr 记录发送端的 socket 地址

addrlen 指定该地址的长度

sendto()往 socket 上写入数据,buff 和 len 参数分别指定写缓冲区的位置和数据长

dest_addr 指定接收数据端的 socket 地址

addrlen 指定该地址的长度

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

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

3.2 服务器端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd==-1){printf("socket err\n");exit(1);}struct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("bind err\n");exit(0);}while(1){int len=sizeof(caddr);char buff[128]={0};recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);printf("buff=%s\n",buff);sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
​
​}close(sockfd);exit(0);
​
}

3.3 客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd==-1){printf("socket err\n");exit(1);}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");while(1){print("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}sendto(sockfd,buff,strlen(buff)-1,0,(struct sockaddr*)&saddr,sizeof(saddr));memset(buff,0,128);recvfrom(sockfd,buff,127,0,NULL,NULL);printf("buff=%s\n",buff);
​}close(sockfd);exit(0);
​
​
}

四、TCP和UDP区别

TCP安全、可靠、面向连接,但是传输速度慢。UDP不安全、不可靠、面向非连接,但是传输速度快。

TCP更适合与文件传输,如果出现错误,会重发。

UDP更适合于实时性,如视频通话,在网卡的情况下,卡住,网好后,能够将实时的画面更新,而不会把之前的再发一遍。

 

相关文章:

Linux Day18 TCP_UDP协议及相关知识

一、网络基础概念 1.1 网络 网络是由若干结点和连接这些结点的链路组成&#xff0c;网络中的结点可以是计算机&#xff0c;交换机、 路由器等设备。 1.2 互联网 把多个网络连接起来就构成了互联网。目前最大的互联网就是因特网。 网络设备有&#xff1a;交换机、路由器、…...

【Java 基础篇】Java网络编程实时数据流处理

在现代计算机应用程序中&#xff0c;处理实时数据流是一项关键任务。这种数据流可以是来自传感器、网络、文件或其他源头的数据&#xff0c;需要即时处理并做出相应的决策。Java提供了强大的网络编程工具和库&#xff0c;可以用于处理实时数据流。本文将详细介绍如何使用Java进…...

Oracle 和 mysql 增加字段SQL

在Oracle和MySQL中&#xff0c;可以使用ALTER TABLE语句来增加字段。下面是分别是两种数据库增加字段的SQL示例&#xff1a; 在Oracle中增加字段的SQL示例&#xff1a; ALTER TABLE 表名ADD (新字段名 数据类型);例如&#xff0c;如果要在名为"employees"的表中添加…...

【脚本】 【Linux】循环执行命令

loop.sh #!/bin/bashif [ "" "$1" ]; thenecho 用法: ./loop.sh 命令内容 时间间隔(毫秒) 循环次数(小于0表示无限循环)echo 示例: ./loop.sh "ps -ef" 1000 10exit 0 fiinterval1000 if [ "" ! "$2" ]; thenif echo &quo…...

快速用Python进行数据分析技巧详解

概要 一些小提示和小技巧可能是非常有用的&#xff0c;特别是在编程领域。有时候使用一点点黑客技术&#xff0c;既可以节省时间&#xff0c;还可能挽救“生命”。 一个小小的快捷方式或附加组件有时真是天赐之物&#xff0c;并且可以成为真正的生产力助推器。所以&#xff0…...

BD就业复习第二天

Hbase 1. 架构 HBase&#xff08;Hadoop Database&#xff09;是一个开源的分布式、面向列族&#xff08;Column Family&#xff09;的NoSQL数据库&#xff0c;它是构建在Hadoop之上的。HBase的架构设计旨在处理大规模的数据&#xff0c;特别适用于需要快速读写和随机访问大量…...

大数据Flink(八十五):Window TVF 支持多维数据分析

文章目录 Window TVF 支持多维数据分析 一、Grouping Sets 二、​​​​​​​Rollup...

css-边框原理教程

1. CSS中边框原理 他不是一条直线&#xff0c;根据盒子原理&#xff0c;当边框宽度大于元素的长和宽时&#xff0c;呈现一个梯形和三角形的形状&#xff0c;用如下的代码来实地理解一下边框画法实现的原理 注&#xff1a;学习网址&#xff1a; CSS画几种图形的方法_css画图_老…...

【数据结构】时间、空间复杂度

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 时间、空间复杂度 1. 算法效率3. 时…...

Databend 开源周报第 111 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 理解 SHARE END…...

iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程

文章目录 一、环境准备二、基础软件三、扩展&#xff1a;usb拓展插件 一、环境准备 1、下载VMware虚拟机的壳子&#xff0c;安装并注册软件(可以百度注册码)&#xff0c;最新版本&#xff1a;v17 2、下MacOS系统iOS镜像文件&#xff0c;用于vmware虚拟机安装&#xff0c;当前镜…...

vue3 - Vue 项目处理GitHub Pages 部署后 _plugin-vue_export-helper.js 404

GitHub Demo 地址 在线预览 vue3项目打包后部署到github pages 后&#xff0c;预览网站提示下划线开头的一个文件_plugin-vue_export-helper访问不到&#xff0c;网络请求显示404 处理GitHub Pages 部署 _plugin-vue_export-helper.js 404 https://github.com/rollup/rollup/b…...

一百八十一、Hive——海豚调度HiveSQL任务时当Hive的计算引擎是mr或spark时脚本的区别(踩坑,附截图)

一、目的 当Hive的计算引擎是spark或mr时&#xff0c;发现海豚调度HQL任务的脚本并不同&#xff0c;mr更简洁 二、Hive的计算引擎是Spark时 &#xff08;一&#xff09;海豚调度脚本 #! /bin/bash source /etc/profile nowdatedate --date0 days ago "%Y%m%d" y…...

Linux 隔离网段下端口转发

设备在隔离网段下&#xff0c;设置端口转发。使A设备可访问C设备的服务 #!/bin/bash #输出成绩脚本 echo -n "请输入外网服务器的IP地址&#xff1a;" read score sudo iptables -t nat -A PREROUTING -p tcp --dport 1883 -j DNAT --to-destination $score:1883 s…...

【CDN和UDN】CDN和UDN技术特点以及使用场景

内容分发网络&#xff08;CDN&#xff09;和用户自定义网络&#xff08;UDN&#xff09;是两种不同的网络技术&#xff0c;在选择时&#xff0c;往往不能准备把握具不同的技术特点和应用场景。CDN 主要用于加速内容分发&#xff0c;而 UDN 则主要用于支持用户自定义的网络需求。…...

【Linux】改变缓存路径、清理缓存

写在前面 在做项目的过程中&#xff0c;服务器base路径下空间不足&#xff0c;准备在另一个目录下创建虚拟环境&#xff0c;但在安装的过程中&#xff0c;发现base路径下的空间还是在减少&#xff0c;后来经过学习了解到&#xff0c;pip安装下载依赖包时&#xff0c;会先下载缓…...

python+opencv寻找图片或视频中颜色进行追踪之HSV颜色处理

pythonopencv寻找图片或视频中颜色进行追踪之HSV颜色处理 1.颜色空间转换 import cv2img cv2.imread(1.jpg) # 转换为灰度图 img_gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)cv2.imshow(img, img) cv2.imshow(gray, img_gray) cv2.waitKey(0)cv2.cvtColor()用来进行颜色模…...

ubuntu 22.04 服务器网卡无IP地址

ssh连接服务器连接不上&#xff0c;提示如下&#xff1b; 连接显示器&#xff0c;ip addr ls 命令查看IP地址&#xff0c;有网卡但没有IP地址 solution&#xff1a; sudo dhclient enp10s0用于通过 DHCP 协议获取网络配置信息并为名为 enp10s0 的网络接口分配 IP 地址,enp1…...

基于SpringBoot的网上点餐系统

目录 前言 一、技术栈 二、系统功能介绍 用户功能模块 管理员功能模块 美食店功能模块 前台首页功能模块 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 系统管理也都将通过计算机进行整体智能化操作&#xff0c;对于网上点餐系统所牵扯的管理及数据保存…...

浅谈xss

XSS 简介 XSS,全称Cross Site Scripting,即跨站脚本攻击,是最普遍的Web应用安全漏洞。这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中,当正常用户访问该页面时,则可导致嵌入的恶意脚本代码的执行,从而达到恶意攻击用户的目的。需要强调的是,XSS不仅…...

悬崖边:企业如何应对网络安全漏洞趋势

在本文中&#xff0c;我们将讨论企业在处理漏洞时面临的挑战&#xff0c;解释安全漏洞是如何引发网络攻击的&#xff0c;以及为什么它会导致不可接受的事件。我们还将分享我们在识别趋势性漏洞方面的经验。 现代信息安全方法正在成为企业的工作流程。例如&#xff0c;不久前&a…...

MyBatis 动态 SQL、MyBatis 标签、MyBatis关联查询

MyBatis 动态 SQL、MyBatis 标签、MyBatis关联查询 1、MyBatis动态 sql 的特性2、MyBatis 标签2.1、if 标签&#xff1a;条件判断2.2、whereif 标签2.3、set 标签2.4、choose(when,otherwise) 语句2.5、trim2.6、MyBatis foreach 标签 3、整合案例3.1、XML3.2、测试类 4、sql 标…...

在Vue中使用Immutable.js

在Vue3中使用Immutable.js 以下是如何在Vue.js中使用Immutable.js的步骤&#xff1a; 首先&#xff0c;需要安装immutable.js。你可以通过npm或yarn来安装&#xff1a; npm install immutable或者 yarn add immutable在你的Vue组件中导入Immutable&#xff1a; import { Ma…...

基于Yolov8的工业端面小目标计数检测(1)

1.端面小目标计数数据集介绍 工业端面小目标计数类别:一类,类别名object 数据集大小:训练集864张,验证集98张 缺陷特点:小目标计数,检测难度大,如下图所示; 1.1 小目标定义 1)以物体检测领域的通用数据集COCO物体定义为例,小目标是指小于3232个像素点(中物体是指…...

1.什么是jwt?jwt的作用是什么?2.jwt的三个部分是什么?三者之间的关系如何?3.JWT运行的流程是什么

1. **什么是JWT&#xff1f;JWT的作用是什么&#xff1f;** JWT&#xff08;JSON Web Token&#xff09;是一种用于在不同系统或组件之间传输信息的紧凑且安全的标准。它的作用主要有两个方面&#xff1a; - **身份验证&#xff08;Authentication&#xff09;**&#xf…...

十三、MySql的视图

文章目录 一、前言二、定义三、为什么使用视图四、基本使用&#xff08;—&#xff09;创建视图&#xff08;二&#xff09;案例1.修改了视图&#xff0c;对基表数据有影响2.修改了基表&#xff0c;对视图有影响3.删除视图 五、视图规则和限制 一、前言 通过视图&#xff0c;可…...

MFC扩展库BCGControlBar Pro v33.6亮点 - 流程图、Ribbon Bar功能升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v33.6已正式发布了&#xff0c;此版本包含了对图表组件的改进、带隐藏标签的单类功能区栏…...

前端 JS 经典:文件流下载

重点&#xff1a;调用接口时&#xff0c;一定要配置 responseType 的值为 blob&#xff0c;不然获取的文件流&#xff0c;不会转义成 blob 类型的文件。 1. 接口返回文件流 // BLOB (binary large object)----二进制大对象&#xff0c;是一个可以存储二进制文件的容器 // 下载…...

SSL免费证书会报安全提示吗?

安全性是互联网世界中至关重要的一环&#xff0c;其中一个关键组成部分就是SSL证书&#xff0c;它们用于加密在用户浏览器和服务器之间传输的数据&#xff0c;以确保数据的保密性和完整性。然而&#xff0c;有关SSL证书的一个常见问题是&#xff1a;免费SSL证书是否会触发安全警…...

为什么要选择Spring cloud Sentinel

为什么要选择Spring cloud Sentinel &#x1f34e;对比Hystrix&#x1f342;雪崩问题及解决方案&#x1f342;雪崩问题&#x1f342;.超时处理&#x1f342;仓壁模式&#x1f342;断路器&#x1f342;限流&#x1f342;总结 &#x1f34e;对比Hystrix 在SpringCloud当中支持多…...

网页设计毕业论文审批表/pc优化工具

百科&#xff1a;http://baike.baidu.com/link?urlatVCMfHUCkH7fdWmP41OL_kpyAmACcij4ffVTGg_mXtgoequLcIp1BwIiIJz7NyIPJhlWhvW7zs2L1HuhhDSOq <ehcache> <!--磁盘存储配置&#xff1a;用来指定缓存在磁盘上的存储位置。 可以使用JavaVM环境变量(user.home, user.di…...

网站二级页怎么做/巨量数据官网

.NET快速开发平台成功案例之大型ERP人事工资考勤系统|C/S框架网本文所指的大型ERP人事工资考勤系统由珠海市喜鹊信息技术有限公司与2012年7月开始研发&#xff0c;2013年12月正式上线Beta版&#xff0c;上线过渡期2个月&#xff0c;共历时16个月&#xff0c;总投资180万。2014年…...

网站营销队伍/培训机构在哪个平台找

前言 现在Java程序员面试都是因为没有丰富的工作经验和自己过硬的技术&#xff0c;所有都不知道一般互联网应该会问什么技术问题&#xff0c;加上自己可能去面试的时候没有准备的太充分&#xff0c;一面试刚跟面试官扯几个面试题就不知道自己在哪里了&#xff0c;被怼的体无完…...

网站认证收费吗/营销推广外包公司

今天很是郁闷&#xff0c;因为我以下的这些文字是第二次打入&#xff0c;艾&#xff0c;断线&#xff0c;提交失败&#xff0c;数据清空 &#xff0c;看来要改进我的后台系统了…… 前段时间&#xff0c;我编写了一套ASPMSSQL的房产程序&#xff1b;今天有一位用户找到我说&…...

淘宝联盟网站建设不完整/上海哪家优化公司好

突然感觉自己菜到不能再菜了&#xff0c;写OJ也有一年了&#xff0c;DP没用过&#xff0c;BFS一点没看&#xff0c;DFS跟没学过一样&#xff0c;现在模拟都模拟不过了&#xff0c;看看别的学院别的学校的大佬们&#xff0c;自己天天自闭也没学多少东西&#xff0c;看来还是不够…...

有什么免费ppt模板网站/sem投放

// 智能指针会自动释放所指向的对象。 // shared_ptr的应用场景是&#xff1a;程序需要在多个对象间共享数据/* 先从应用场景入手吧&#xff0c;说矿工A发现了一个金矿。* 然后矿工A喊来了矿工B&#xff0c;一起开采&#xff0c;不久后矿工A劳累过度死了。* 矿工B继续开采着矿工…...