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

网络编程(8.14)TCP并发服务器模型

作业:
1. 多线程中的newfd,能否修改成全局,不行,为什么?
2. 多线程中分支线程的newfd能否不另存,直接用指针间接访问主线程中的newfd,不行,为什么?
多线程并发服务器模型原代码:

#include<stdio.h>
#include<head.h>
#include<netinet/in.h>
#define PROT 1112
#define IP "192.168.125.133"
void handler(int sig)
{while(waitpid(-1,NULL,WNOHANG)>0);
}
struct climsg
{int nfd;struct sockaddr_in cin;};
void* deal_cli_msg(void *arg);
int main(int argc, const char *argv[])
{//捕获17信号if(signal(17,handler)==SIG_ERR){   ERR_MSG("signal");return -1; }   //创建流式套接字int sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd<0){   ERR_MSG("socket");return -1; }   printf("sfd=%d\n",sfd);//设置允许端口被快速复用int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0){   ERR_MSG("setsockopt");return -1; }   printf("允许端口快速复用成功\n");//绑定服务器的IP和端口--->必须绑定struct sockaddr_in sin;sin.sin_family      = AF_INET;//必须填AF_INETsin.sin_port        = htons(PROT);//端口号:1024~49151sin.sin_addr.s_addr = inet_addr(IP);//本机IPif(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){   ERR_MSG("bind");return -1; }   printf("绑定成功\n");//将套接字设置为被动监听状态if(listen(sfd,128)<0){   ERR_MSG("listen");return -1; }   printf("被动监听状态设置成功\n");//从已完成连接的队列中获取一个客户端信息,生成一个新的文件描述符struct sockaddr_in cin;//存储客户端地址信息socklen_t addrlen = sizeof(cin);pthread_t tid;int nfd=-1;struct climsg info;while(1){   nfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);if(nfd<0){ERR_MSG("accept");return -1; }printf("[%s:%d]nfd=%d,客户端连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),nfd);info.nfd=nfd;info.cin=cin;//该文件描述符才是客户端通信的文件描述符if(pthread_create(&tid,NULL,deal_cli_msg,(void *)&info)!=0){printf("pthread_create failed __%d__\n",__LINE__);return -1; }}   close(sfd);return 0;
}
void* deal_cli_msg(void *arg)
{char buf[128]="";ssize_t res=0;int nfd =((struct climsg*) arg)->nfd;struct sockaddr_in cin =((struct climsg*) arg)->cin;while(1){   bzero(buf,sizeof(buf));//接受数据res=recv(nfd,buf,sizeof(buf),0);if(res<0){ERR_MSG("recv");break;}else if(0==res){printf("[%s:%d]nfd=%d 客户端下线\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),nfd);break;}printf("nfd=%d : %s\n",nfd,buf);//发送数据strcat(buf,"*_*");if(send(nfd,buf,sizeof(buf),0)<0){ERR_MSG("send");break;}printf("发送成功\n");}close(nfd);return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                           
} 

1.将newfd改成全局变量效果:

 答:不行,因为newfd是全局变量的话,客户端连接后生成的新的文件描述符会一直覆盖上一次保存的文件描述符,导致客户端下线时只能关闭最新创建的文件描述符,无法关闭之前客户端连接时创建的文件描述符。

2.不保存分支线程的newfd,直接用指针间接访问主线程中的newfd效果:

与第一题效果相同,不保存nfd时有客户端创建连接会一直覆盖结构体里的文件描述符nfd的数据,导致断开连接时关闭的文件描述符nfd取的是结构体里最新的 ,导致之前创建连接时开启的文件描述符没有被保存导致无法关闭。

3.基于UDP的TFTP文件传输

TFTP通信过程总结

  1. 服务器在69号端口等待客户端的请求
  2. 服务器若批准此请求,则使用 临时端口 与客户端进行通信。
  3. 每个数据包的编号都有变化(从1开始)
  4. 每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
  5. 数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束。

 

 下载代码:

#include<stdio.h>
#include<head.h>
#define PORT 69
int main(int argc, const char *argv[])
{char IP[128]="";printf("请输入IP:\n");scanf("%s",IP);char name[128]="";printf("请输入文件名:\n");scanf("%s",name);//创建报式套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd<0){   ERR_MSG("socket");return -1; }   printf("sfd=%d\n",sfd);//填充客户端自身的地址信息结构体,真实的地址信息结构体根据地址族指定//AF_INET : man 7 ip;                                                                                                                                                                                                                                                                                                                                                                                                                                               struct sockaddr_in sin;sin.sin_family      = AF_INET;//必须填AF_INETsin.sin_port        = htons(PORT);//服务器端口号:1024~49151sin.sin_addr.s_addr = inet_addr(IP);//服务器IP ifconfig查看ssize_t res=0;struct sockaddr_in rcvaddr;socklen_t addrlen = sizeof(rcvaddr);char data[516]="";//数据包char ACK[4]="";//ACK包size_t i=4;char *p=data;short *p1=(short*)data;*p1=htons(1);char *p2=data+2;strcpy(p2,name);char *p3=p2+strlen(p2)+1;strcpy(p3,"octet");//发送读写请求if(sendto(sfd,p,(i+strlen(p2)+strlen(p3)),0,(struct sockaddr*)&sin,sizeof(sin))<0){   ERR_MSG("sendto");return -1; }   bzero(data,sizeof(data));int fp=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);while(1){   //接收数据res=recvfrom(sfd,data,sizeof(data),0,(struct sockaddr*)&rcvaddr,&addrlen);if(res<0){   ERR_MSG("recvfrom");return -1; }   if(write(fp,data+4,res-4)<0){   ERR_MSG("write");close(fp);return -1; }   if(res<516){   printf("传输完毕\n");break;}//发送数据short *m1=(short *)ACK;*m1=htons(4);short *m2=m1+1;*m2=*((short *)data+1);if(sendto(sfd,ACK,i,0,(struct sockaddr*)&rcvaddr,sizeof(rcvaddr))<0){ERR_MSG("sendto");return -1; }bzero(data,sizeof(data));bzero(ACK,sizeof(ACK));}   //关闭文件描述符close(sfd);close(fp);return 0;
} 

上传代码:

http://www.lryc.cn/news/130917.html

相关文章:

  • 认识负载均衡||WEBSHELL
  • Chapter 15: Object-Oriented Programming | Python for Everybody 讲义笔记_En
  • 模板编程-成员特化
  • 信安通用基础知识
  • 网上购物系统的设计与实现/在线商城/基于spring boot的电商平台/基于Java的商品销售系统
  • uniapp项目-配置store文件夹
  • element表格多选实现
  • 宠物智能自动喂食器方案设计
  • 学习笔记230818---对于promise失败状态处理的重要性
  • 【Redis】什么是缓存击穿,如何预防缓存击穿?
  • Android 13.0 强制app横屏显示
  • 平方数之和(力扣)双指针 JAVA
  • 深入浅出Pytorch函数——torch.nn.init.sparse_
  • OpenCV实现BGR2BayerGB/BG格式的转换
  • Gateway网关路由以及predicates用法(项目中使用场景)
  • 深入浅出Pytorch函数——torch.nn.init.constant_
  • centos mysql8解决Access denied for user ‘root‘@‘localhost‘ (using password: YES)
  • Docker实战:Docker常用命令
  • 基于51单片机直流电机转速数码管显示控制系统
  • 小程序商品如何指定打印机
  • LLaMA-7B微调记录
  • 域名子目录发布问题(nginx、vue-element-admin、uni-app)
  • 【环境配置】Windows 10 安装 PyTorch 开发环境,以及验证 YOLOv8
  • 数学建模之“层次分析法”原理和代码详解
  • 使用IText导出复杂pdf
  • 多线程并发服务器(TCP)
  • uni-app的Vue.js实现微信小程序的紧急事件登记页面功能
  • 面试题 17.16.按摩师
  • vscode里配置C#环境并运行.cs文件
  • uniapp配置添加阿里巴巴图标icon流程步骤