测试代码:
#define _DEFAULT_SOURCE
#include<arpa/inet.h>
#include<unistd.h>
#include<stdbool.h>
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#define lv_exit(fd,str) \
if(fd<0) {\
perror(str);\
exit(1);\
}
static void handle_connect(int fd,char* buf,ssize_t len,struct sockaddr_in cliaddr,socklen_t clilen)
{
printf("from : %s %d %d=%s",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port),getpid(), buf);
len=sendto(fd,buf,len,0,(void*)&cliaddr,clilen);
lv_exit(len,"sendto");
sleep(10);
printf("getpid %d %s\n",getpid(),"end");
exit(0);
}
void my_exit(int status)
{
puts("my_exit");
exit(1); //调用回调函数
}
void function(int status,void *arg){
printf("fd=%d\n",(int)arg);
int ret=close((int)arg);
lv_exit(ret,"close");
}
int main(int argc, char const *argv[])
{
int fd=socket(AF_INET,SOCK_DGRAM,0);
lv_exit(fd,"socket");
struct sockaddr_in seraddr;
seraddr.sin_family=AF_INET;
seraddr.sin_port=htons(9999);
seraddr.sin_addr.s_addr=inet_addr("192.168.244.154");
int bret=bind(fd,(void*)&seraddr,sizeof seraddr);
lv_exit(bret,"bind");
signal(SIGCHLD,SIG_IGN); //避免僵尸进程
signal(SIGINT,my_exit); //回收fd
on_exit(function,(void*)fd);//注册回调函数
while (1)
{
struct sockaddr_in cliaddr;
socklen_t clilen=sizeof cliaddr;
char buf[512]={0};
ssize_t len= recvfrom(fd,buf,sizeof(buf)-1,0,(void*)&cliaddr,&clilen);
lv_exit(len,"recvfrom");
int fk=fork();
if(fk>0)continue;
handle_connect(fd,buf,len,cliaddr,clilen);
}
return 0;
}测试流程:
启动服务器:
启动客户端

小结:客户端每发送一次数据,服务器端都会启动一个进程,开销比较大,后续准备使用进程池优化
编译遇到警告如图所示:此类告警可以忽略是我们故意为之,不懂的朋友可以留言。

0.0分
0 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复