2024.5.21 作业 xyt

今日课堂内容:域套接字

TCP流式套接字

//服务器
#include <myhead.h>
int main(int argc, const char *argv[])
{//1、为通信创建一个端点int sfd = socket(AF_UNIX, SOCK_STREAM, 0);//参数1:说明使用的是ipv4通信域//参数2:说明使用的是TCP面向连接的通信方式//参数3:由于参数2中已经指定通信方式,填0即可if(sfd == -1){perror("socket error");return -1;}printf("socket success sfd = %d\n", sfd);   //3//判断要绑定的套接字文件是否存在?if(access("./unix", F_OK) == 0){//说明文件存在,要将其删除if(unlink("./unix") ==-1){perror("unlink error");return -1;}}//2、绑定ip和端口号//2.1 准备地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;    //通信域strcpy(sun.sun_path , "./unix");         //套接字文件路径//2.2 绑定工作:必须绑定一个不存在的套接字文件if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) ==-1){perror("bind error");return -1;}printf("bind success\n");//3、将套接字设置成被动监听状态if(listen(sfd, 128)==-1){perror("listen error");return -1;}printf("listen success\n");//4、阻塞等待客户端的连接//4.1 定义用于接受客户端信息的容器struct sockaddr_un cun;socklen_t addrlen = sizeof(cun);int newfd = accept(sfd, (struct sockaddr*)&cun, &addrlen);if(newfd == -1){perror("accept error");return -1;}printf("[%s]:发来连接请求\n", cun.sun_path);//5、与客户端进行相互通信char rbuf[128] = "";            //读取消息内容的容器while(1){//清空容器bzero(rbuf, sizeof(rbuf));//从套接字中读取数据//int res = read(newfd, rbuf, sizeof(rbuf));int res = recv(newfd, rbuf, sizeof(rbuf), 0);if(res == 0){printf("客户端已经下线\n");break;}//将读取的消息展示出来printf("[%s]:%s\n", cun.sun_path, rbuf);//将收到的消息处理一下,回复给客户端strcat(rbuf, "*_*");//讲消息发送给客户端//write(newfd, rbuf, strlen(rbuf));send(newfd, rbuf, strlen(rbuf), 0);printf("发送成功\n");}//6、关闭套接字close(newfd);close(sfd);return 0;
}
//客户端
#include <myhead.h>
int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int cfd = socket(AF_UNIX, SOCK_STREAM, 0);if(cfd == -1){perror("socket error");return -1;}printf("cfd = %d\n", cfd);            //3//判断要绑定的套接字文件是否存在?if(access("./linux", F_OK) == 0){//说明文件存在,要将其删除if(unlink("./linux") ==-1){perror("unlink error");return -1;}}//2、绑定IP地址和端口号 ?//2.1 填充客户端地址信息结构体struct sockaddr_un cun;cun.sun_family = AF_UNIX;strcpy(cun.sun_path, "./linux");//2.2 绑定if( bind(cfd, (struct sockaddr*)&cun, sizeof(cun)) ==-1){perror("bind error");return -1;}printf("bind success\n");//3、连接服务器//3.1 准备对端地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./unix");//3.2 连接服务器if(connect(cfd, (struct sockaddr*)&sun, sizeof(sun))==-1){perror("connect error");return -1;}printf("connect success\n");//4、数据收发char wbuf[128] = "";char rbuf[128] = "";while(1){//从终端上获取要发送的数据fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf)-1] = '\0';           //将读取的换行改成'\0'//将数据发送给服务器send(cfd, wbuf, strlen(wbuf), 0);printf("发送成功\n");//接收服务器发来的消息bzero(rbuf, sizeof(rbuf));recv(cfd, rbuf, sizeof(rbuf), 0);printf("服务器发来的消息为:%s\n", rbuf);}//5、关闭套接字close(cfd);return 0;
}

UDP报式套接字

//服务器
#include <myhead.h>
int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int sfd = socket(AF_UNIX, SOCK_DGRAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("sfd = %d\n", sfd);            //3//判断要绑定的套接字文件是否存在?if(access("./unix", F_OK) == 0){//说明文件存在,要将其删除if(unlink("./unix") ==-1){perror("unlink error");return -1;}}//2、绑定IP地址和端口号//2.1 填充地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./unix");//2.2 绑定if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) ==-1){perror("bind error");return -1;}printf("bind success\n");//3、数据收发char rbuf[128] = "";//准备接受对端的地址信息struct sockaddr_un cun;socklen_t addrlen = sizeof(cun);while(1){//清空容器bzero(rbuf,sizeof(rbuf));//读取数据//read(sfd, rbuf, sizeof(rbuf));recvfrom(sfd, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&cun, &addrlen);printf("[%s]:%s\n", cun.sun_path, rbuf);//将收到的消息,加个笑脸回过去strcat(rbuf, "*_*");//if(write(sfd, rbuf, strlen(rbuf))==-1)if(sendto(sfd, rbuf, strlen(rbuf), 0, (struct sockaddr*)&cun, sizeof(cun))==-1){perror("write error");return -1;}printf("发送成功\n");}//4、关闭套接字close(sfd);return 0;
}
//客户端
#include <myhead.h>
int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int cfd = socket(AF_UNIX, SOCK_DGRAM, 0);if(cfd == -1){perror("socket error");return -1;}printf("cfd = %d\n", cfd);            //3//2、绑定套接字文件//2.1 填充地址信息结构体struct sockaddr_un cun;cun.sun_family = AF_UNIX;strcpy(cun.sun_path, "./linux");//判断要绑定的套接字文件是否存在?if(access("./linux", F_OK) == 0){//说明文件存在,要将其删除if(unlink("./linux") ==-1){perror("unlink error");return -1;}}//2.2 绑定if(bind(cfd, (struct sockaddr*)&cun, sizeof(cun)) ==-1){perror("bind error");return -1;}printf("bind success\n");//3、数据收发char wbuf[128] = "";//填充服务器的地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./unix");char rbuf[128] = "";while(1){//清空容器bzero(wbuf,sizeof(wbuf));bzero(rbuf, sizeof(rbuf));//从终端上获取信息fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf)-1] = 0;//讲消息发送给服务器sendto(cfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&sun, sizeof(sun));printf("发送成功\n");//接受服务器发来的消息recvfrom(cfd, rbuf, sizeof(rbuf), 0,NULL, NULL);printf("收到服务器消息为:%s\n", rbuf);}//4、关闭套接字close(cfd);return 0;
}

项目作业:

#include <myhead.h>
#define SER_PORT 69
void download(int fd,struct sockaddr_in sin);
void upload(int fd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{/*1.判断终端输入 */if(argc !=2 ){printf("ip未输入\n");exit(-1);}/*2. 创建套接字 */int fd;if((fd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("socket");exit(1);}/*3. 向结构体中录入服务器信息 */struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(argv[1]);/*4. 功能实现 */while(1){/*4.1 打印提示表 */printf("**********************\n");printf("********1.下载********\n");printf("********2.上传********\n");printf("********3.退出********\n");printf("**********************\n");/*4.2. 文件传输 */int S_opcode=0;scanf("%d",&S_opcode);while(getchar()!=10);switch (S_opcode){/*7.1 下载文件  */case 1:download(fd,sin);break;/*7.2 上传文件 */case 2:upload(fd,sin);break;case 3:goto _EXIT;break;default:printf("输入不正确\n");break;}}/*5. 退出 */
_EXIT:close(fd);return 0;
}
/* 下载 */
void download(int fd,struct sockaddr_in sin){int num=1;int flag=0;int wpid=-1;char Rsever_buf[516]={0};/*1. 与服务端进行数据传输 *//*1.1 初始化 */char Wsever_buf[516]="";//写入服务端的字符串/*1.2 第一次数据建立准备 *//*1.2.1 文件操作码选择 */short *opcode=(short *)Wsever_buf;*opcode=htons(1);/*1.2.2 文件名传输 */char *filename=Wsever_buf+2;printf("请输入文件名:");char filestr[32]="";fgets(filestr,32,stdin);filestr[strlen(filestr)-1]=0;strcpy(filename,filestr);/*1.2.3 传输模式 */char *mode=filename+strlen(filename)+1;strcpy(mode,"octet");/*1.2.4 数据大小统计 */int size=2+strlen(filename)+strlen(mode)+2;/*2. 第一次读写请求传输 */if(sendto(fd,Wsever_buf,size,0,(struct sockaddr *)&sin,sizeof(sin))<0){perror("sendto");exit(-1);}	while(1){/*3. 读取服务端数据包 */bzero(Rsever_buf,sizeof(Rsever_buf));socklen_t addrlen=sizeof(sin);ssize_t recv_len=-1;if((recv_len=recvfrom(fd,Rsever_buf,sizeof(Rsever_buf),0,(struct sockaddr *)&sin,&addrlen))<0){perror("recvfrom");exit(-1);}/*3. 判断操作码及编号 */short *r_opcode =(short *)Rsever_buf;short *r_num=r_opcode+1;switch (htons(*r_opcode)){/*3.1 正确数据包处理*/case 3:if(*r_num==htons(num)){printf("正在下载中\n");num++;break;}else{printf("数据包编号错误\n");exit(-1);}/*3.2 错误数据包提示 */case 5:if(0==htons(*r_num)){printf("未定义,差错错误信息\n");return;}else if(1==htons(*r_num)){printf("File not found\n");return;}else if(2==htons(*r_num)){printf("Access violation\n");return;}else if(3==htons(*r_num)){printf("Disk full or allocation exceeded\n");return;}else if(4==htons(*r_num)){printf("illegal TFTP operation\n");return;}else if(5==htons(*r_num)){printf("Unknown transfer ID\n");return;}else if(6==htons(*r_num)){printf("File already exists\n");return;}else if(7==htons(*r_num)){printf("No such user\n");return;}else if(8==htons(*r_num)){printf("Unsupported option(s) requested\n");return;}break;default:break;}/*4. 打开文件 */if(0==flag){wpid=open(filename,O_WRONLY | O_CREAT |O_TRUNC,0666);if(wpid<0){perror("open");exit(-1);}flag=1;}/*5. 写入文件 */if(write(wpid,Rsever_buf+4,recv_len-4)<0){printf("%s\n",Wsever_buf+4);perror("write");break;}/*6. ACK确认回馈 */char ACK[4]={0};short *w_opcode=(short *)ACK;*w_opcode=htons(4);short *w_num=w_opcode+1;*w_num=*r_num;/*7. 传输ACK确认包 */if(sendto(fd,ACK,4,0,(struct sockaddr *)&sin,sizeof(sin))<0){perror("sendto");exit(-1);}/*8. 判断文件是否下载结束 */if(recv_len<516){printf("文件下载完成\n");close(fd);break;}}
}
/*上传*/
void upload(int fd,struct sockaddr_in sin){int num=0;int flag=0;char Rsever_buf[516]={0};/*1. 与服务端进行数据传输 *//*1.1 初始化 */char Wsever_buf[516]="";//写入服务端的字符串/*1.2 第一次数据建立准备 *//*1.2.1 文件操作码选择 */short *opcode=(short *)Wsever_buf;*opcode=htons(2);/*1.2.2 文件名传输 */char *filename=Wsever_buf+2;printf("请输入文件名:");char filestr[32]="";fgets(filestr,32,stdin);filestr[strlen(filestr)-1]=0;strcpy(filename,filestr);/*1.2.2.1. 打开文件 */int wpid=-1;if((wpid=open(filename,O_RDONLY))<0){printf("文件名不存在,请重新输入\n");return;}/*1.2.3 传输模式 */char *mode=filename+strlen(filename)+1;strcpy(mode,"octet");/*1.2.4 数据大小统计 */int size=2+strlen(filename)+strlen(mode)+2;/*2. 第一次读写请求传输 */if(sendto(fd,Wsever_buf,size,0,(struct sockaddr *)&sin,sizeof(sin))<0){perror("sendto");exit(-1);}	while(1){/*3. 读取服务端数据包 */bzero(Rsever_buf,sizeof(Rsever_buf));socklen_t addrlen=sizeof(sin);ssize_t recv_len=-1;if((recv_len=recvfrom(fd,Rsever_buf,sizeof(Rsever_buf),0,(struct sockaddr *)&sin,&addrlen))<0){perror("recvfrom");exit(-1);}/*3. 判断操作码及编号 */short *r_opcode =(short *)Rsever_buf;short *r_num=r_opcode+1;switch (htons(*r_opcode)){/*3.1 正确数据包处理*/case 4:if(*r_num==htons(num)){printf("正在上传中\n");num++;*r_num=htons(num);break;}else{printf("数据包编号错误\n");break;}/*3.2 错误数据包提示 */case 5:if(0==htons(*r_num)){printf("未定义,差错错误信息\n");return;}else if(1==htons(*r_num)){printf("File not found\n");return;}else if(2==htons(*r_num)){printf("Access violation\n");return;}else if(3==htons(*r_num)){printf("Disk full or allocation exceeded\n");return;}else if(4==htons(*r_num)){printf("illegal TFTP operation\n");return;}else if(5==htons(*r_num)){printf("Unknown transfer ID\n");return;}else if(6==htons(*r_num)){printf("File already exists\n");return;}else if(7==htons(*r_num)){printf("No such user\n");return;}else if(8==htons(*r_num)){printf("Unsupported option(s) requested\n");return;}break;default:break;}/*4. 读取文件内容 */int retval=-1;if((retval=read(wpid,Rsever_buf+4,512))<0){perror("read");break;}else if(0==retval){printf("文件上传完毕\n");return;}/*5. 文件上传 */*r_opcode=htons(3);if(sendto(fd,Rsever_buf,retval+4,0,(struct sockaddr *)&sin,sizeof(sin))<0){perror("sendto");return;}}
}

今日课堂提问:

1.项目中如何实现TCP的并发?
答:
在项目中实现 TCP 的并发通常涉及创建多个独立的执行流程来处理同时发起的多个 TCP 连接。常用的方法有以下几种:

1. **多进程**:服务端为每个新的客户端连接创建一个新的进程。这种方法的优点是简单易理解,每个进程独立运行,容错性好。但缺点是进程创建和切换的开销较大,不适合大量并发连接。

2. **多线程**:服务端为每个新的客户端连接创建一个新的线程。相比多进程,多线程的开销较小,因为线程间切换的成本低于进程间切换,共享资源的管理也比较方便。但多线程程序设计相对复杂,需要妥善处理同步和并发问题。

3. **I/O 多路复用**:通过选择性地阻塞在多个 I/O 上,例如使用 select、poll 或 epoll(在 Linux 上)等系统调用,服务器可以在单线程或少量线程中管理多个客户端连接。当某个 I/O 流准备好进行读写操作时,系统会通知服务器程序,从而进行相应的处理。

在实现 TCP 并发时,还需要考虑到负载均衡、资源管理、错误处理等问题,以确保服务器的稳定和性能。选择哪一种方法取决于具体的应用需求、性能要求和开发资源。
2.TCP通信过程中的三次握手?
答:
TCP的三次握手应用于建立连接:
第一次握手:客户端向服务器发送一个SYN包(同步包),其中包含客户端的初始序列号。此时,客户端进入SYN_SEND状态,等待服务器的确认。
第二次握手:服务器收到SYN包后,会确认客户端的SYN(通过发送一个ACK包,其中ack=客户端的序列号+1),同时服务器也会发送一个自己的SYN包,其中包含服务器的初始序列号。这个包通常被称为SYN+ACK包。此时,服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的SYN+ACK包后,会再次发送一个ACK包以确认收到服务器的SYN包(ack=服务器的序列号+1)。发送完这个ACK包后,客户端和服务器都进入ESTABLISHED状态,表示连接已建立成功。
简记:同步包→同步包+应答包→应答包

3.四次挥手的过程?
答:
TCP的四次挥手应用于释放连接,需要进行的四个步骤,具体步骤如下:
第一次挥手:当一方(假设为客户端)决定关闭连接时,它会发送一个FIN(Finish)报文段给对方。
第二次挥手:服务器收到FIN报文段后,会对这个FIN报文段进行确认,然后自己也发送一个ACK报文段。
第三次挥手:服务器在发送完ACK报文段后,会等待所有的数据传输完成,然后发送一个FIN报文。
第四次挥手:客户端收到服务器的FIN报文段后,会对其进行确认,并发送一个ACK报文段给服务器。
简记:FIN包→应答包→FIN包→应答包
                          ​​​​​​​​​​​​​​
4.tcp\IP协议分几层?tcp\IP是哪一层?
答:
TCP/IP 协议模型通常分为四层,这些层次分别是:

1. **网络接口层**:也称为链接层或网络访问层,它负责通过网络媒体发送和接收数据包,包括定义电缆的物理和电气标准。

2. **互联网层**:它主要负责数据包在网络中的传输,确保数据包能够跨越多个网络从源到达目的地。互联网协议(IP)就处在这一层。

3. **传输层**:这一层提供端到端的通信服务,确保数据的成功传输。TCP(传输控制协议)和 UDP(用户数据报协议)都处于这一层。

4. **应用层**:它负责处理特定的应用程序细节,提供了网络服务与最终用户应用程序之间的接口。例如,HTTP、FTP、SMTP 等协议都工作在这一层上。

从协议的名称“TCP/IP”来看,“TCP”指的是传输控制协议,位于传输层;“IP”指的是互联网协议,位于互联网层。因此,“TCP/IP”实际上涉及到模型中的两个不同层次:传输层和互联网层。
​​​​​​​​​​​​​​
5.UDP为什么丢包,怎样处理?丢包发生在哪一层?为什么?
答:
​​​​​​​​​​​​​​UDP(用户数据报协议)丢包的原因包括:

1. **无连接性**:UDP 是一种无连接的协议,不像 TCP 那样在数据传输之前建立连接。这意味着UDP不保证可靠传输,数据包可能会在传输过程中丢失。

2. **无拥塞控制**:UDP 本身不进行拥塞控制。当网络拥塞时,UDP 继续以相同的速率发送数据包,这可能导致网络设备(如路由器)的缓冲区溢出,从而丢包。

3. **无序传输**:UDP 不保证数据包的顺序,所以数据包到达顺序可能与发送顺序不同,接收方需要处理可能的乱序问题。

4. **无错误校验重传机制**:TCP 有检验和及确认应答机制,并会重传损坏的数据包。而 UDP 只有基本的检验和功能,但不会重传损坏或丢失的数据包。

处理 UDP 丢包的方法包括:

- **应用层重传机制**:在需要可靠性的应用中,可以在应用层实现重传机制。如果在预定的时间内没有收到数据包的应答,发送方可以重发数据包。

- **序列号**:在数据包中引入序列号,以便接收方能够检测到丢包事件,并且能够将乱序到达的数据包重新排列成正确的顺序。

- **冗余数据**:使用前向错误校正(FEC)等技术,在传输数据中加入额外的冗余数据,这样即使某些数据包丢失,接收方也可能恢复出原始数据。

- **调节发送速率**:根据网络的实时状况调整数据的发送速率,避免因网络拥塞造成丢包。

- **使用其他协议**:对于需要高可靠性的应用,可以考虑使用更可靠的协议,如 TCP,或者更先进的协议,例如 QUIC。

- **应用选择重传(Selective Acknowledgment, SACK)**:这是一种在接收端告知发送端只重传丢失的数据包,而不是所有后续数据的机制。

丢包发生在网络层原因:

网络拥堵:当网络中的数据流量超过了网络设备(如路由器或交换机)的处理能力时,这些设备的缓冲区可能会满,导致无法继续接收新的数据包。当缓冲区满时,新到达的数据包将被丢弃。网络拥堵是导致丢包最常见的原因之一。
路由问题:数据包在网络层按照路由算法确定的路径从源头路由到目标。如果路由配置错误或是动态路由算法遇到问题,可能导致数据包被错误地发送到不存在或无法到达的目的地,从而导致丢包。
硬件故障:网络设备的物理损坏或故障也可能导致丢包。例如,路由器的接口损坏,导线问题,或其他硬件故障都可能阻止数据包的正确传输。
链路质量差:无线网络或长距离传输中的信号衰减、干扰、噪声等问题也是导致丢包的常见原因。在这些情况下,数据包在传输过程中可能会变得不完整或损坏,接收端设备无法正确解析这些数据包,导致丢包。
包过大:如果数据包的大小超过了网络中间设备的最大传输单元(MTU),而且数据包没有设定允许分片或者路径上的某个设备不支持分片,那么这个数据包会被丢弃。
安全策略:为了安全考虑,一些网络设备可能配置了包过滤或防火墙规则,用于阻止特定类型的流量。符合这些规则的数据包将被丢弃。

 6.TCP是同步还是异步?谈谈你对同步异步的理解?
答:
​​​​​​​​​​​​​​TCP(传输控制协议)本身在底层是同步的,因为它需要建立连接,在发送方和接收方之间传输数据,并确认数据包已接收。TCP确保数据准确无误地从一个网络端点传递到另一个网络端点。

对于**同步**(Synchronous)来说,它通常指的是操作的发起者必须等待这个操作完成才能继续进行后续的操作。在同步操作中,任务按照它们发生的顺序依次执行,每个任务的完成是下一个任务开始的前提。例如,当你进行网络请求,在得到响应之前,程序将不会执行后续代码,这是同步操作的特点。

而**异步**(Asynchronous)操作则不同,异步意味着操作的发起者不必等待操作完成就可以继续执行后续的操作。在异步执行中,可以启动一个任务,并且在它完成之前就开始执行其他任务。当该任务完成时,程序会在适当的时间处理完成的操作。这种方式允许程序在等待长时间操作(如文件读写、网络请求等)的同时,继续执行其他代码,从而优化程序的整体性能。

系统中的同步和异步操作常常结合起来使用,以实现更高效、可靠的数据处理和通信。应用程序根据不同的需要,可能采用同步或异步模式来处理任务,或者结合使用二者的特点。例如,在一个TCP服务中,尽管TCP协议是同步的,但应用层可以采用异步编程模型来管理多个TCP连接,以提高系统的并发能力和性能。

7.什么是TCP的沾包现象,如何解决?
答:
​​​​​​​​​​​​​​TCP的粘包现象(sticky packets phenomenon)是指在使用TCP进行通信时,由于TCP是一个面向字节流的协议,它会将应用程序的数据看作一串无结构的字节流,数据包之间的界限并不是固定的。因此,当发送方连续快速发送多个较小的消息时,TCP可能将它们合并为一个较大的数据包来提高效率,同样,接收方也可能一次性读取并合并多个数据包。这就可能导致接收端不能确定每个数据包的边界,即发生粘包。

解决粘包问题一般有以下几种方法:

1. **消息定界**:为每个消息设置边界,如使用特殊的分隔符或序列来标识消息的开始和结束。接收方在接收数据时,根据这些定界符来分割原始字节流,从而恢复出独立的消息。

2. **固定长度**:每个消息都采用固定的长度,这样接收方就可以在接收到对应长度的数据后进行处理。

3. **消息长度字段**:在消息的开始处添加一个长度字段,这个长度字段指示了整个消息的长度,接收方首先读取长度字段,然后读取相应长度的数据作为一个消息。

4. **组合方法**:在消息开始处既指定消息的长度又包含一些结束符,确保接收方能准确无误地分割消息。

5. **应用层协议设计**:设计实用的应用层协议来处理消息的封包和解包。例如,HTTP、FTP等应用层协议都有自己的处理方式来防止粘包问题。

6. **利用现成的框架和库**:许多网络编程库(如Netty、asyncio等)提供了解决粘包问题的机制,无需手动处理粘包,只需要按库的规定编写逻辑即可。

在应用层实现这些策略可以避免TCP粘包现象,确保数据能够正确、完整地在客户端和服务器之间传输。

8.组播和广播的区别?
答:
​​​​​​​​​​​​​​组播(Multicast)和广播(Broadcast)是网络通信中用于发送消息给多个目的地的两种机制:

1. **广播**:
   - 广播是一对所有的通信方式,其中一台主机发送的消息将传送给同一局域网(LAN)上的所有其他主机。
   - 广播消息通常用在没有特定目标的情况下,例如,当新设备加入网络并寻址DHCP服务器以获取IP地址时,它会发送广播消息。
   - 广播地址对于所有设备都是公开和可识别的,就像把信件扔进一个房间让每个人都能拿去阅读。
   - 在广播中,网络中的每台设备即使对消息不感兴趣也会收到消息,这可能导致无用的网络流量和设备处理。

2. **组播**:
   - 组播允许将消息同时发送给一组指定的目的地(即组播组中的主机)。只有加入该组的主机才会接收组播消息。
   - 组播地址仅适用于那些已经表明愿意接收该特定组播组消息的设备。
   - 组播有效地支持了多点传输,仅将消息传递给感兴趣的监听者,这样就减少了网络的拥堵和无效流量。
   - 组播广泛用于流媒体、实时应用和网络服务中,例如视频会议和在线游戏,典型的例子有IGMP(Internet Group Management Protocol)和多播路由。

总结来说,广播是将消息发送给所有人,而组播是将消息仅发送给一组感兴趣的监听者。组播比广播更有效率,因为它减少了不必要的数据传输。

9.阻塞IO和非阻塞IO的区别?
答:
​​​​​​​​​​​​​​阻塞IO(Blocking IO)和非阻塞IO(Non-blocking IO)主要区别体现在程序如何等待IO操作完成:

1. **阻塞IO**:
   - 在阻塞IO模型中,当一个IO操作(如读取或写入)开始时,如果数据没有准备好,程序会被挂起(即阻塞),直到数据准备好并且IO操作完成。
   - 在数据准备阶段,程序做不了其他事情,它会等待在那里直到整个IO操作完全完成后才会继续执行。
   - 阻塞IO简化了编程模型,因为在发起IO请求之后,你只需要等待结果,不必担心在这个过程中如何处理其他任务。

2. **非阻塞IO**:
   - 非阻塞IO模型中,IO操作不会导致程序挂起等待。如果数据没有准备好,IO调用会立即返回一个指示数据尚未准备好的状态。
   - 程序可以继续执行后续代码,它可以定期地检查IO操作是否可以进行,或者可以进行其他工作,这样很好地利用了等待时间。
   - 非阻塞IO通常与事件驱动或轮询机制一起使用,程序可以在多个IO操作之间有效地切换,提高了程序的整体效率和响应性。

非阻塞IO更适用于处理高并发情况,尤其在需要同时管理多个连接或者进行多个并行IO操作时。但这种模型编程难度较高,因为要管理和调度多个IO操作,而且可能需要额外的机制(如IO复用或事件通知)来检测IO状态。

10.并发和并行的区别?
答:
并发(Concurrency)和并行(Parallelism)是计算机科学中两个关键概念,常常用来描述处理多个任务的能力,它们之间有着本质的区别:

1. **并发**:
   - 并发是指一个处理单元(如CPU)在同一时间段内处理多个任务的能力。它更多地关注多任务的交错执行,即任务在单个核心上通过上下文切换实现多任务的“同时”处理。
   - 并发不是真正的同时执行多个操作,而是从宏观角度看,使得每个任务都有机会按顺序执行,从而给用户一种多个任务同时处理的错觉。
   - 并发更多地应用于任务处理的组织和调度上,常用于单核或多核处理器上的任务管理,以提高资源的使用效率和系统的响应速度。

2. **并行**:
   - 并行是指多个处理单元(如多个CPU核心)同时执行多个任务或操作。在并行计算中,每个处理单元都在同一时刻独立地执行不同的任务,实现了真正的同时处理。
   - 并行计算侧重于通过增加计算资源来增加计算速度,适用于有大量计算需要分割执行的场景,如大规模科学计算、图像处理等。
   - 在多核和多处理器系统中,并行计算可以显著提高计算效率和处理速度,特别是对于可以明确分解和独立执行的任务。

简而言之,**并发是任务交错执行**(在单个核心上“同时”处理多个任务),**并行是多个核心同时执行任务**。并发的目的在于充分利用有限的计算资源以提高效率,而并行的目标是通过增加计算资源来减少计算时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/17673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML静态网页成品作业(HTML+CSS)——动漫海绵宝宝介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

【前端笔记】记录一个能优化Echarts Geo JSON大小的网站

前端在使用Echarts等可视化图表库会不可避免遇到的问题&#xff0c;渲染地图的数据太大。 而有那么一个网站能给予这个问题一个解决方案&#xff1a;链接在此 使用方法很简单&#xff0c;首先先进入网站&#xff0c;如果进入了会是这个页面&#xff1a; 接着&#xff0c;选择一…

HCIP的学习(25)

VLAN间通讯技术 使用多臂路由的方式 ​ 路由器的物理接口默认是不识别802.1Q标签的&#xff0c;所以&#xff0c;交换机连接路由器的接口在发送数据帧时&#xff0c;应该将标签剥离。----一般常使用Access接口配置。 单臂路由 ​ 所谓的单臂路由&#xff0c;实际上试讲路由器…

【主流分布式算法总结】

文章目录 分布式常见的问题常见的分布式算法Raft算法概念Raft的实现 ZAB算法Paxos算法 分布式常见的问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;…

Docker是什么?使用场景作用及Docker的安装和启动详解

目录 Docker是什么&#xff1f; Docker的发展 Docker的安装 Docker使用 Docker的运行机制 第一个Docker容器 进入Docker容器 客户机访问容器 Docker是什么&#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker …

记录深度学习GPU配置,下载CUDA与cuDnn

目标下载: cuda 11.0.1_451.22 win10.exe cudnn-11.0-windows-x64-v8.0.2.39.zip cuda历史版本网址 CUDA Toolkit Archive | NVIDIA Developer 自己下载过11.0.1版本 点击下载local版本,本地安装,有2个多GB,很大,我不喜欢network版本,容易掉线 cuDnn https://developer.nvi…

设置AXI主寄存器切片和AXI数据FIFO

设置AXI主寄存器切片和AXI数据FIFO 打开MHS文件&#xff0c;并为每个AXI主机设置启用寄存器切片/启用数据FIFO。到 确定正确的设置&#xff0c;使用下表中的信息搜索MHS。 进行搜索时&#xff0c;将<intf_name>替换为相关的BUS_INTERFACE名称。 例如&#xff0c;BUS_INTE…

Docker部署SpringBoot项目(jar包+Mysql)

部署Java项目 项目准备准备Java项目镜像准备配置网络 部署项目细节展示 项目准备 准备Java项目 hmall项目是一个maven聚合项目&#xff0c;使用IDEA打开hmall项目&#xff0c;查看项目结构如图&#xff1a; 我们要部署的就是其中的hm-service&#xff0c;其中的配置文件采用…

还在使用Swagger吗?ApifoxHelper插件隆重登场

目录 前言 安装Apifox Idea插件安装 插件令牌配置 获取令牌 Idea配置令牌 快速上手 同步文档 查看文档 结语&#xff1a; 前言 最近发现一款特别好用的插件&#xff0c;帮助开发者快速生成接口文档。ApifoxHelper插件实现代码零侵入&#xff0c;只需要写上相应注释即可…

K8s种的service配置

什么是service 官方的解释是:   k8s中最小的管理单元是pod&#xff1b;而service是 将运行在一个或一组 Pod 上的网络应用程序公开为网络服务的方法;   Kubernetes 中 Service 的一个关键目标是让你无需修改现有应用以使用某种服务发现机制。 你可以在 Pod 集合中运行代码…

K-独立钻石(dfs),G-邪恶铭刻(贪心)

这两题&#xff0c;都是应该赛场上A出来的。 K.独立钻石 当时一直关注点在 I. Path Planning&#xff0c;没关注榜单&#xff0c;K,也能写&#xff0c;也就是dfs,从数据范围可以看出&#xff0c;直接暴力搜索。 代码 #include<bits/stdc.h> #define int long long #d…

读书短视频脚本:四川京之华锦信息技术公司

读书短视频脚本&#xff1a;打造引人入胜的文学世界 随着短视频平台的兴起&#xff0c;各类内容以更加直观、生动的方式呈现在观众面前。在这个信息爆炸的时代&#xff0c;如何将书籍的精华和魅力通过短视频这一新兴媒介传递给更多人&#xff0c;成为了一个值得探讨的话题。四…

C# 正则表达式使用小计

此文档用于记录平时使用正则表达式的心得&#xff0c;不定期更新 基础 实例 替换实例一 //这里匹配以 “( 开头,以 )” 结尾的字符串 private static Regex REGEX_ARG_CONTENT new Regex("""(.*?)""");//此方法用于在匹配到的结果前添加字符…

【教程】利用API接口添加本站同款【每日新闻早早报】-每天自动更新,不占用文章数量

本次分享的是给网站添加一个每日早报的文章&#xff0c;可以看到本站置顶上面还有一个日更的日报&#xff0c;这是利用ALAPI的接口完成的&#xff01;利用接口有利也有弊&#xff0c;因为每次用户访问网站的时候就会增加一次API接口请求&#xff0c;导致文章的请求会因为请求量…

【python】删除一个列表中的所有的1

删除所有的1 x [1, 1, 6, 3, 9, 4, 5, 1, 1, 2, 1, 9, 6, 4] 使用lambda函数和filter来过滤掉x中的1 filtered_x list(filter(lambda n: n ! 1, x)) 不是1的数字&#xff0c;存进x列表&#xff0c;filter用于插入元素到第二个位置 print(filtered_x) # 输出: [6, 3, 9, …

Discourse 编辑没有办法显示更多的 JS 错误

Priority/Severity: High Platform: 3.3.0.beta3-dev UI bugs Description: 昨天升级的时到最新版本的时候就发现有这个错误&#xff0c;是 JS 的错误。 发了一个帖子到官方的网站上&#xff0c;官方说可能是插件的问题。 但是我们实在是没有安装什么插件呀&#xff1f; 官方…

“一带一路”六国国际拳王冠军赛特克斯站新闻发布会顺利举行

实习记者&#xff1a;喀兰姆罕 5月24日&#xff0c;“一带一路”六国国际拳王冠军赛特克斯站新闻发布会在特克斯县阿克塔斯姑娘峰景区举行。这次拳王冠军赛事由新疆广播电视台、特克斯镇人民政府&#xff0c;特克斯县文化体育广播电视和旅游局主办&#xff0c;将于6月15日在特…

宿舍管理系统代码详解(操作界面)

目录 一、前端代码 1.样式展示 2.代码详解 <1>主页面列表部分 &#xff08;1&#xff09;template部分 &#xff08;2&#xff09;script部分 <2>新增页面 &#xff08;1&#xff09;template部分 &#xff08;2&#xff09;script部分 <3>修改页面…

NXP i.MX8系列平台开发讲解 - 3.13 Linux 之Audio子系统(二)

专栏文章目录传送门&#xff1a;返回专栏目录 目录 1. Linux ALSA 内核框架 2. Linux ALSA 代码分析 2.1 声卡驱动初始化 2.2 声卡创建注册 2.3 PCM设备创建 3. ALSA ASoC 3.1 Machine 3.2 Platform 3.3 Codec 上一章节&#xff0c;对于Linux Audio子系统有了大概的了解…

LabVIEW通过以太网控制PLC程序开发

在使用LabVIEW通过以太网控制PLC程序开发时&#xff0c;需要综合考虑硬件、软件和通信协议的协调工作。以下是详细步骤、注意事项、重点和难点分析&#xff0c;以及几种实现方式及其特点的概述。 实现步骤 确定硬件和软件环境&#xff1a; 确定PLC型号和品牌&#xff08;如西门…