顺德网站建设公司有哪些,住房和城乡建设部网站评估,百度搜索推广的五大优势,app的网站域名注册并发服务器概念#xff1a; 并发服务器同一时刻可以处理多个客户机的请求 设计思路#xff1a; 并发服务器是在循环服务器基础上优化过来的 #xff08;1#xff09;每连接一个客户机#xff0c;服务器立马创建子进程或者子线程来跟新的客户机通信 #xff08;accept之后…并发服务器概念 并发服务器同一时刻可以处理多个客户机的请求 设计思路 并发服务器是在循环服务器基础上优化过来的 1每连接一个客户机服务器立马创建子进程或者子线程来跟新的客户机通信 accept之后的服务器不会与客户端进行通信 2IO多路复用技术 1、多进程实现并发服务器
思想 主进程专门用于连接多个客户端的请求若有一路客户端连接进来主进程就创建一个子进程用该子进程来处理该客户端的业务数据。 回顾创建进程 #include sys/types.h #include unistd.h pid_t fork(void); 功能创建一个子进程 参数无 返回值pid_t就是int类型的别名 返回值大于0代表此时是父进程该值的含义为创建成功的子进程的ID号 返回值等于0代表此时是子进程 返回值小于0创建失败可以perror 源代码
tcp_server.c
#include sys/types.h
#include sys/socket.h
#include stdio.h
#include string.h
#include netinet/in.h//sockaddr_in
#include unistd.h
#include arpa/inet.h // 包含 inet_addr 函数的声明
#include sys/select.h
#include sys/time.h
#define BUF_SIZE 20int main(int argc, const char *argv[])
{//1.socketint iServer socket(AF_INET, SOCK_STREAM, 0);if(-1 iServer){puts(----------1、create socket error!);return -1;}printf(----------1、create socket ok! iServer:%d, iServer);//012标准输入输出出错iServer为3//2.bindstruct sockaddr_in stServer;stServer.sin_family AF_INET;//第一个成员stServer.sin_port htons(8888);//第二个成员stServer.sin_addr.s_addr inet_addr(127.0.0.1);//将点分十进制ip地址转换为32位无符号整数int ret bind(iServer, (struct sockaddr *)stServer, sizeof(struct sockaddr));if(-1 ret){puts(----------2、bind error!);return -1;}puts(----------2、bind ok!);//3.listenret listen(iServer, 5);if(-1 ret){puts(----------3、listen error!);return -1;}puts(----------3、listen ok!);//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len sizeof(struct sockaddr_in);char buf[BUF_SIZE] {0};fd_set stFdr;//文件描述符集合表大小1024FD_ZERO(stFdr);//将文件描述符集合表中所有内容清零while(1){FD_SET(iServer, stFdr);FD_SET(0, stFdr);//selectret select(iServer 1, stFdr, NULL, NULL, NULL);if(ret 0){continue;}printf(select ok, ret %d\r\n, ret);//FD_ISSETif(FD_ISSET(0, stFdr)){memset(buf, 0, BUF_SIZE);fgets(buf, BUF_SIZE, stdin);printf(fgets ok, data %s\r\n, buf);}if(FD_ISSET(iServer, stFdr)){int iClient accept(iServer, (struct sockaddr *)stClient, len);if(-1 iClient){continue;//当前客户端出错转向下一个客户端 }printf(----------4、accept ok! iClient %d\r\n,iClient );//标准输入输出出错所以下一个打开的文件一定是3//5.recv/sendret recv(iClient, buf, BUF_SIZE, 0);if(ret 0){close(iClient);continue;}printf(----------recv data ok! buf %s\r\n,buf);//sendret send(iClient, buf, BUF_SIZE, 0);if(ret 0){close(iClient);continue;}printf(----------send data ok! %s\r\n,buf);//close(iClient);//断开当前客户端}}return 0;
}
tcp_client.c
#include stdio.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include unistd.h#define BUF_SIZE 20
//main函数参数如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{//1、socketint iClient socket(AF_INET, SOCK_STREAM, 0);if(-1 iClient){puts(----------1、create socket error!);return -1;}puts(----------1、create socket ok!);//2、connectstruct sockaddr_in stServer;stServer.sin_family AF_INET;stServer.sin_port htons(8888);//stServer.sin_addr.s_addr inet_addr(192.168.15.71);stServer.sin_addr.s_addr inet_addr(127.0.0.1);int ret connect(iClient, (struct sockaddr *)stServer, sizeof(struct sockaddr_in));if(-1 ret){puts(----------2、connect error!);return -1;}puts(----------2、connect ok!);char buf[BUF_SIZE] {0};while(1){//gets();//char *fgets(char *s, int size, FILE *stream);fgets(buf, BUF_SIZE, stdin);//更安全边界检查//3、send recvret send(iClient, buf, BUF_SIZE, 0);if(-1 ret){puts(----------3、send data error!);}printf(----------3、send data ok! buf %s\r\n,buf);//recv//函数原型ssize_t recv(int sockfd, void *buf, size_t len, int flags);memset(buf, 0, BUF_SIZE);ret recv(iClient, buf, BUF_SIZE, 0);if(-1 ret){puts(----------4、recv error!);return -1;}printf(----------4、recv data ok! buf %s\r\n,buf);}close(iClient);return 0;
}
思考 多进程并发服务器的缺点每连接一个客户端就为其创建子进程客户端数量比较大时服务器的运 行效率就会变低。 注 以上代码只能实现 ①客户端连接到服务器端只能发送一条数据之后发送不成功 ②服务器端可以检测标准输入给自己 测试结果如下图 2、多进程实现并发服务器-优化版本
tcp_server.c
#include sys/types.h
#include sys/socket.h
#include stdio.h
#include string.h
#include netinet/in.h//sockaddr_in
#include unistd.h
#include arpa/inet.h // 包含 inet_addr 函数的声明
#include sys/select.h
#include sys/time.h
#define BUF_SIZE 20int main(int argc, const char *argv[])
{//1.socketint iServer socket(AF_INET, SOCK_STREAM, 0);if(-1 iServer){puts(----------1、create socket error!);return -1;}printf(----------1、create socket ok! iServer:%d, iServer);//012标准输入输出出错iServer为3//2.bindstruct sockaddr_in stServer;stServer.sin_family AF_INET;//第一个成员stServer.sin_port htons(9999);//第二个成员stServer.sin_addr.s_addr inet_addr(127.0.0.1);//将点分十进制ip地址转换为32位无符号整数int ret bind(iServer, (struct sockaddr *)stServer, sizeof(struct sockaddr));if(-1 ret){puts(----------2、bind error!);return -1;}puts(----------2、bind ok!);//3.listenret listen(iServer, 5);if(-1 ret){puts(----------3、listen error!);return -1;}puts(----------3、listen ok!);//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len sizeof(struct sockaddr_in);char buf[BUF_SIZE] {0};fd_set stFdr;//文件描述符集合表大小1024FD_ZERO(stFdr);//将文件描述符集合表中所有内容清零FD_SET(iServer, stFdr);//iServer添加到原文件描述符集合表中int max iServer;while(1){//selectfd_set stFdrTmp stFdr; //定义临时文件描述符集合表ret select(max 1, stFdrTmp, NULL, NULL, NULL);if(ret 0){printf(select error!\r\n);continue;}printf(select ok, ret %d\r\n, ret);int i 0;for(i 0; i max 1; i){if(FD_ISSET(i, stFdrTmp)){ // 循环判断哪个文件描述符被置位//操作if(i iServer){ // i 3, 操作int iClient accept(iServer, (struct sockaddr *)stClient, len);if(-1 iClient){continue;//当前客户端出错转向下一个客户端 }printf(----------4、accept ok! iClient %d\r\n,iClient );//标准输入输出出错所以下一个打开的文件一定是4FD_SET(iClient, stFdr);//更新maxif(max iClient){max iClient;}}else{ // 与多个客户端保持连接//recv/sendret recv(i, buf, BUF_SIZE, 0);if(ret 0){printf(recv:%s\r\n, buf);send(i, buf, BUF_SIZE, 0);}else{close(i);FD_CLR(i, stFdr);}}}}}return 0;
}tcp_client.c
#include stdio.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include unistd.h#define BUF_SIZE 20
//main函数参数如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{//1、socketint iClient socket(AF_INET, SOCK_STREAM, 0);if(-1 iClient){puts(----------1、create socket error!);return -1;}puts(----------1、create socket ok!);//2、connectstruct sockaddr_in stServer;stServer.sin_family AF_INET;stServer.sin_port htons(9999);//stServer.sin_addr.s_addr inet_addr(192.168.15.71);//stServer.sin_addr.s_addr inet_addr(192.168.15.71);stServer.sin_addr.s_addr inet_addr(127.0.0.1);int ret connect(iClient, (struct sockaddr *)stServer, sizeof(struct sockaddr_in));if(-1 ret){puts(----------2、connect error!);return -1;}puts(----------2、connect ok!);char buf[BUF_SIZE] {0};while(1){//gets();//char *fgets(char *s, int size, FILE *stream);fgets(buf, BUF_SIZE, stdin);//更安全边界检查//3、send recvret send(iClient, buf, BUF_SIZE, 0);if(-1 ret){puts(----------3、send data error!);}printf(----------3、send data ok! buf %s\r\n,buf);//recv//函数原型ssize_t recv(int sockfd, void *buf, size_t len, int flags);memset(buf, 0, BUF_SIZE);ret recv(iClient, buf, BUF_SIZE, 0);if(-1 ret){puts(----------4、recv error!);return -1;}printf(----------4、recv data ok! buf %s\r\n,buf);}close(iClient);return 0;
}
注 以上代码可以实现 ①多个客户端与服务器连接 并 发送回显数据 测试结果如下图