目录

1.并发服务器

1)多进程并发服务器

2)多线程并发服务器

2.域套接字

1.流式域套接字(TCP)

1.1服务器

1.2客户端

2.报式套接字(UDP)

2.1服务器

2.2客户端


1.并发服务器

可以同时处理多个客户端的请求,创建子进程或者分支线程来处理客户端处理客户端的请求。

父进程/主线程只负责连接,子进程/分支线程只负责与客户端交互。

1)多进程并发服务器

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__);\perror(msg);\
}while(0)
#define PORT    8888
#define IP      "192.168.31.160"  //本机IP:ifconfig查看
typedef void (*sighandler_t)(int);int rcv_cli_msg(int newfd, struct sockaddr_in cin);void handler(int sig)
{while(waitpid(-1, NULL, WNOHANG) > 0);
}
int main(int argc, const char *argv[])
{//捕获17号信号,用信号的方式回收僵尸进程sighandler_t s = signal(SIGCHLD, handler);if(SIG_ERR == s){ERR_MSG("signal");return -1;}//创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket");return -1;}//允许端口快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速重用设置成功\n");//填充IP和端口到地址信息结构体中,实际结构体是由地址族决定://AF_INET --> man 7 ipstruct sockaddr_in sin;sin.sin_family=AF_INET;             //地址族必须指定为AF_INETsin.sin_port=htons(PORT);         //端口号的网络字节序:1024~49151sin.sin_addr.s_addr=inet_addr(IP);    //ubuntu的本机IP:ifconfig可以查看//绑定服务器的IP地址和端口,必须绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0){ERR_MSG("bind");return -1;}printf("bind success\n");//将套接字设置为被动监听状态if(listen(sfd, 10) < 0){ERR_MSG("listen");return -1;}printf("listen success\n");struct sockaddr_in cin ;        //接收客户端的IP和端口socklen_t addrlen = sizeof(cin);int newfd;pid_t pid;while(1){//父进程只负责连接,即只负责运行accept函数//获取新的文件描述符,该文件描述符才是用于通信、交互的文件描述符newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("[%s:%d] newfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);//能运行到当前位置,则代表有客户端连接成功//所以需要创建一个子进程用于 与客户端进行交互pid = fork();if(0 == pid){close(sfd);//子进程运行:只负责与客户端交互rcv_cli_msg(newfd, cin);//因为子进程只负责交互,当运行到当前位置时候,与客户端的交互就已经结束了close(newfd);exit(0);}else if(pid > 0){//父进程运行:负责与客户端连接,newfd是用于交互的,所以newfd对于父进程来说没有用close(newfd);}else{ERR_MSG("fork");return -1;}}close(sfd);return 0;
}
int rcv_cli_msg(int newfd, struct sockaddr_in cin)
{char buf[128] = "";ssize_t res = 0;while(1){bzero(buf, sizeof(buf));res = recv(newfd, buf, sizeof(buf), 0);if(res< 0){ERR_MSG("recv");return -1;}else if(0 == res){fprintf(stderr, "[%s:%d] newfd=%d 客户端关闭\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);break;}printf("[%s:%d] newfd=%d : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, buf);strcat(buf, "!!!");if(send(newfd, buf, sizeof(buf), 0) < 0){ERR_MSG("send");return -1;}printf("发送成功\n");}return 0;
}

运行效果:

2)多线程并发服务器

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__);\perror(msg);\
}while(0)
#define PORT    8888
#define IP      "192.168.31.160"
//需要传入到线程处理函数的内容
struct msg
{int newfd;struct sockaddr_in cin;
};
//线程执行体
void* callBack(void* arg)
{struct msg info = *(struct msg*)arg;int newfd = info.newfd;struct sockaddr_in cin = info.cin;char buf[128] = "";ssize_t res = 0;while(1){bzero(buf, sizeof(buf));res=recv(newfd, buf, sizeof(buf), 0);if(res< 0){ERR_MSG("recv");break;}else if(0 == res){fprintf(stderr, "[%s:%d] newfd=%d 客户端关闭\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);break;}printf("[%s:%d] newfd=%d : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, buf);strcat(buf, "!!!");if(send(newfd, buf, sizeof(buf), 0) < 0){ERR_MSG("send");break;}printf("发送成功\n");}close(newfd);pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket");return -1;}//允许端口快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速重用设置成功\n");//填充IP和端口到地址信息结构体中,实际结构体是由地址族决定://AF_INET --> man 7 ipstruct sockaddr_in sin;sin.sin_family=AF_INET;           //地址族必须指定为AF_INETsin.sin_port=htons(PORT);         //端口号的网络字节序:1024~49151sin.sin_addr.s_addr=inet_addr(IP);    //ubuntu的本机IP:ifconfig可以查看//绑定服务器的IP地址和端口,必须绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0){ERR_MSG("bind");return -1;}printf("bind success\n");//将套接字设置为被动监听状态if(listen(sfd, 10) < 0){ERR_MSG("listen");return -1;}printf("listen success\n");struct sockaddr_in cin ;        //接收客户端的IP和端口socklen_t addrlen = sizeof(cin);int newfd;pthread_t tid;struct msg info;  //该结构体中存储的是需要传入到线程处理函数的变量;while(1){//主线程只负责连接//获取新的文件描述符,该文件描述符才是用于通信、交互的文件描述符newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("[%s:%d] newfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);info.newfd = newfd;info.cin = cin;//能运行到当前位置,则代表有客户端连接成功,//则需要创建一个分支线程处理交互if(pthread_create(&tid, NULL, callBack, (void*)&info) != 0){ERR_MSG("pthread_create");return -1;}//分离线程,分离后线程会自动回收自己的资源;pthread_detach(tid);}close(sfd);return 0;
}

运行结果:

注意: 进程生成的文件描述符相同,线程生成的文件描述符不同

2.域套接字

只能做本地通讯的套接字,地址族指定为AF_UNIX

1.流式域套接字(TCP)

1.1服务器

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/un.h>
#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__);\perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_UNIX, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket");return -1;}//判断要绑定的套接字文件路径是否存在if(access("./unix", F_OK) == 0){//如果存在,则需要将该套接字文件删除if(unlink("./unix") < 0){ERR_MSG("unlink");return -1;}}//填充地址信息结构体,实际结构体是由地址族决定:struct sockaddr_un sun;sun.sun_family=AF_UNIX;           strcpy(sun.sun_path, "./unix");//绑定服务器的IP地址和端口,必须绑定if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) < 0){ERR_MSG("bind");return -1;}printf("bind success\n");//将套接字设置为被动监听状态if(listen(sfd, 10) < 0){ERR_MSG("listen");return -1;}printf("listen success\n");struct sockaddr_un cun ;        //接收客户端的地址信息结构体socklen_t addrlen = sizeof(cun);//获取新的文件描述符,该文件描述符才是用于通信、交互的文件描述符int newfd = accept(sfd, (struct sockaddr*)&cun, &addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("newfd = %d\n", newfd);char buf[128] = "";ssize_t res = 0;while(1){bzero(buf, sizeof(buf));res = recv(newfd, buf, sizeof(buf), 0);if(res< 0){ERR_MSG("recv");return -1;}else if(0 == res){fprintf(stderr, "newfd = %d客户端关闭\n", newfd);break;}printf("newfd=%d : %s\n", newfd, buf);strcat(buf, "!!!");if(send(newfd, buf, sizeof(buf), 0) < 0){ERR_MSG("send");return -1;}printf("发送成功\n");}close(newfd);close(sfd);return 0;
}

1.2客户端

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/un.h>
#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__);\perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_UNIX, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket");return -1;}//绑定客户端自身的IP地址和端口---->非必须绑定 //填充要连接的服务器的地址信息结构体struct sockaddr_un sun;sun.sun_family=AF_UNIX;strcpy(sun.sun_path, "./unix");//连接服务器if(connect(sfd, (struct sockaddr*)&sun, sizeof(sun)) < 0){ERR_MSG("connect");return -1;}printf("connect success\n");char buf[128] = "";ssize_t res ;while(1){bzero(buf, sizeof(buf));printf("请输入:");fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;if(send(sfd, buf, sizeof(buf), 0) < 0){ERR_MSG("send");return -1;}printf("send success\n");bzero(buf, sizeof(buf));res = recv(sfd, buf, sizeof(buf), 0);if(res < 0){ERR_MSG("recv");return -1;}else if(0 ==res){printf("服务器关闭\n");break;}printf(":%s\n", buf);}close(sfd);return 0;
}

本地终端测试:

2.报式套接字(UDP)

2.1服务器

代码:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\
}while(0);
int main(int argc, const char *argv[])
{//创建报式套接字int sfd=socket(AF_UNIX,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}if(access("./unix1",F_OK)==0){if(unlink("./unix1")<0){ERR_MSG("unlink");return -1;}}struct sockaddr_un sun;sun.sun_family=AF_UNIX;strcpy(sun.sun_path,"./unix1");if(bind(sfd,(struct sockaddr*)&sun,sizeof(sun))<0){ERR_MSG("bind");return -1;}printf("bind success\n");char buf[128]="";ssize_t res=0;struct sockaddr_un cun;socklen_t addrlen=sizeof(cun);while(1){bzero(buf,sizeof(buf));res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cun,&addrlen);if(res<0){ERR_MSG("recvfrom");return -1;}printf("[%s]:%s\n",cun.sun_path,buf);strcat(buf,"!!!");if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cun,sizeof(cun))<0){ERR_MSG("sendto");return -1;}printf("sendto success\n");}close(sfd);return 0;
}

2.2客户端

代码:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__);\perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{int sfd=socket(AF_UNIX,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}if(access("./unix2",F_OK)==0){if(unlink("./unix2")<0){ERR_MSG("nulink");return -1;}}struct sockaddr_un cun;cun.sun_family=AF_UNIX;strcpy(cun.sun_path,"./unix2");if(bind(sfd,(struct sockaddr*)&cun,sizeof(cun))<0){ERR_MSG("bind");return -1;}printf("bind success\n");struct sockaddr_un sun;sun.sun_family=AF_UNIX;strcpy(sun.sun_path,"./unix1");char buf[128]="";ssize_t res=0;struct sockaddr_un rcv_addr;socklen_t addrlen=sizeof(rcv_addr);while(1){bzero(buf,sizeof(buf));printf("请输入:");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0;if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sun,sizeof(sun))<0){ERR_MSG("sendto");return -1;}printf("sendto success\n");bzero(buf,sizeof(buf));res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&rcv_addr,&addrlen);if(res<0){ERR_MSG("recvfrom");return -1;}printf("[%s]:%s\n",rcv_addr.sun_path,buf);}close(sfd);return 0;
}

本地终端测试:

华清远见上海中心22071班 9.19作业相关推荐

  1. 华清远见上海中心22071班--11.19作业

    题目:实现开发板点灯操作 程序要求: 1)分部实现注册字符设备驱动 2)自动创建设备节点 3)通过结构体对led灯地址进行映射 4)次设备号完成私有数据传参 5)在open函数中获取到次设备号,用私有 ...

  2. 华清远见上海中心22071班 9.2作业

    1.用父子进程拷贝一张图片,其中子进程先拷贝后半部分,父进程后拷贝前半部分.要求用文件IO实现. 函数: #include <stdio.h> #include <fcntl.h&g ...

  3. 华清远见上海中心22071班 9.7作业

    目录 1.创建两个线程 A.B,要求A线程读取文件中的数据,B线程将读取到的数据打印到终端上,类似shell命令cat. 2.编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自 ...

  4. 华清远见上海中心22071班 9.30作业

    电子词典: 登录注册功能,不能重复登录,重复注册 单词查询功能 历史记录功能,存储单词,意思,以及查询时间 基于TCP,支持多客户端连接 采用数据库保存用户信息与历史记录 将dict.txt的数据导入 ...

  5. 华清远见上海中心22071班 8.24作业

    1.单向链表按位置修改 void list_update_pos(linklist *L,int pos,datatype e) {if(NULL==L||list_empty(L)||pos< ...

  6. 华清远见上海中心22071班 9.21作业

    1.完成数据库的插入.删除.修改,插入选择全字段插入.删除.修改选择用id的方式 代码: #include <stdio.h> #include <sqlite3.h> #in ...

  7. 华清远见上海中心22071班 8.25作业

    目录 1.用无头结点的循环链表实现约瑟夫环问题 头文件: 功能函数: 主函数: 终端输出: 2.顺序栈实现进制转换问题 头文件: 功能函数: 主函数: 终端输出: 1.用无头结点的循环链表实现约瑟夫环 ...

  8. 华清远见上海中心22071班--11.24作业

    题目:应用层采取ioctl命令控制,驱动代码用GPIO子系统,实现开发板6盏灯的循环亮灭 头文件程序: #ifndef __LED_H__ #define __LED_H__typedef enum{ ...

  9. 华清远见上海中心22071班--11.28作业

    题目:三个按键实现按键中断,key1>>led1,key2>>led2, key3>>led3.按键按一下灯亮,再按一下灯灭 . #include <linu ...

最新文章

  1. Swoole入门介绍
  2. [新活动] 2015年推广返利活动
  3. 开发十年的程序员论:零基础自学Python,学习路径是什么?深思
  4. C++容器的选择和详细操作方法总结(有自己总结)
  5. pytorch ResNet结构代码实现
  6. mongodb 字符串转bson_MongoDB之bson的介绍
  7. 汇编语言复习摘要六——包含多个段的程序
  8. Java分页工具实现方法
  9. 国家统计局统计用区划代码和城乡划分代码---爬虫、详细分析
  10. rna聚类分析_新技术助力单细胞RNA测序数据聚类分析
  11. python多进程协同_简单谈谈python中的多进程
  12. Spring Cloud与Dubbo怎么选择?
  13. 关于本人树莓派捣鼓过程中的一些记录
  14. 关联分析(Association Analysis)--挖掘啤酒与尿布的关联规则
  15. HTML5与CSS3学习笔记【第八章 操作样式表】
  16. 类,__dift__,__len__,__add__,__new__,__init__
  17. Linux内核 LCD 驱动程序框架
  18. 摘:一张废手机卡的作用
  19. 给程序员推荐提高工作效率的软件
  20. 树莓派点灯笔记(论如何学好控制IO输出)

热门文章

  1. 使用mspaint改变图片大小的一个小技巧记录
  2. 旅行青蛙(旅かえる)的最全攻略
  3. eDNA检测技术的介绍
  4. 【监控利器Prometheus】——Prometheus+Grafana监控服务器资源
  5. 【模拟CMOS集成电路】电路失调与CMRR—— 随机失调与系统失调分析(1)
  6. 使用脑机接口从神经信号中重建单词
  7. IDEA 打包Web项目为war包
  8. 【python基础】正则表达式总结
  9. apoc插件安装说明
  10. 免费实用的CAD移动端看图软件有它就够了!