多进程、多线程服务器程序
来源:互联网 发布:资管业务 知乎 编辑:程序博客网 时间:2024/06/06 20:08
版本一:
客户端和服务器端可以进行通信,但是只能有一个客户端。
1.服务器端程序tcp_server.c
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>static void Usage(const char *proc){//提示客户端运行时的形式ip+端口号 printf("%s[local_ip][local_port]\n",proc);}int startup(const char *_ip,int _port){ //建立服务器端套接字socket int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(_port); local.sin_addr.s_addr=inet_addr(_ip); //将套接字绑定到网络服务器的地址上 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(3); } //建立监听队列 if(listen(sock,5)<0) { perror("listen"); exit(4); } return sock;}int main(int argc,char *argv[]){ if(argc!=3) { Usage(argv[0]); return 1; } int listen_sock=startup(argv[1],atoi(argv[2])); while(1) { struct sockaddr_in client; socklen_t len=sizeof(client); //等待客户端连接请求到达 int new_fd=accept(listen_sock,(struct sockaddr*)&client,&len); if(new_fd<0) { perror("accept"); continue; } //客户端连接成功 printf("get a new client,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(\ client.sin_port)); while(1) { char buf[1024]; //接收客户端发送的数据 ssize_t s=read(new_fd,buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client: %s\n",buf); write(new_fd,buf,sizeof(buf)-1); } else {//客户端的数据被读完,即连接断开 printf("read done...,break\n"); break; } } }}
2.客户端程序 tcp_client.c
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>static void Usage(const char *proc){//提示客户端运行时的形式ip+端口号 printf("%s[server_ip][server_port]\n",proc);}int main(int argc,char *argv[]){ if(argc!=3) { Usage(argv[0]); return 1; } //建立客户端套接字 int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); return 2; } //服务器端的网络地址结构 struct sockaddr_in remote; remote.sin_family=AF_INET; remote.sin_port=htons(atoi(argv[2])); remote.sin_addr.s_addr=inet_addr(argv[1]); //与远程服务器连接 if(connect(sock,(struct sockaddr*)&remote,sizeof(remote))<0) { perror("connect"); return 3; } while(1) { char buf[1024]; printf("Please Enter#"); //在屏幕上输入数据 fflush(stdout); ssize_t s=read(0,buf,sizeof(buf)-1); if(s>0) { buf[s-1]=0; write(sock,buf,strlen(buf)); ssize_t _s=read(sock,buf,sizeof(buf)-1); if(_s>0) { buf[_s]=0; printf("Server echo#%s\n",buf); } } }}
①先运行服务器端,当客户端连接上服务器端时,服务器端会给出提示:
②客户端向服务器端发送数据,若服务器端接收到数据时,会回显在客户端的屏幕上
③服务器端接收到客户端的数据,当客户端断开连接时,服务器端显示数据已读完
版本二:
多进程服务器:
修改服务器,让服务器端可以被多个客户端连接,实现多用户、多进程
tcp_server.c
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>static void Usage(const char *proc){ printf("%s[local_ip][local_port]\n",proc);}int startup(const char *_ip,int _port){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(_port); local.sin_addr.s_addr=inet_addr(_ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(3); } if(listen(sock,5)<0) { perror("listen"); exit(4); } return sock;}int main(int argc,char *argv[]){ if(argc!=3) { Usage(argv[0]); return 1; } //返回监听套接字 int listen_sock=startup(argv[1],atoi(argv[2])); while(1) { struct sockaddr_in client; socklen_t len=sizeof(client); int new_fd=accept(listen_sock,(struct sockaddr*)&client,&len); if(new_fd<0) { perror("accept"); continue; } printf("get a new client,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(\ client.sin_port)); //创建子进程 pid_t id=fork(); if(id<0) { perror("fork"); close(new_fd); } else if(id==0) {//child close(listen_sock); if(fork()>0) {//子进程退出,子进程的子进程变为孤儿进程,被1号进程回收,让子进程的子进程继续运行程序,父进程不需要再回收子进程 exit(0); } while(1) { char buf[1024]; ssize_t s=read(new_fd,buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client: %s\n",buf); write(new_fd,buf,sizeof(buf)-1); } else { printf("read done...,break\n"); return; } } close(new_fd); } else {//father close(new_fd); } }}
版本三:
多线程服务器:
编译时需要链接线程的库 -lpthread
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>static void Usage(const char *proc){//提示客户端运行时的形式ip+端口号 printf("%s[local_ip][local_port]\n",proc);}int startup(const char *_ip,int _port){ //建立服务器套接字 int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(_port); local.sin_addr.s_addr=inet_addr(_ip); //将套接字绑定到网络服务器的地址上 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(3); } //建立监听队列 if(listen(sock,5)<0) { perror("listen"); exit(4); } return sock;}void *handlerRequest(void *arg){//处理客户端数据 int new_fd=(int)arg; while(1) { char buf[1024]; ssize_t s=read(new_fd,buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client: %s\n",buf); write(new_fd,buf,sizeof(buf)-1); } else { printf("read done...,break\n"); break; } }}int main(int argc,char *argv[]){ if(argc!=3) { Usage(argv[0]); return 1; } int listen_sock=startup(argv[1],atoi(argv[2])); while(1) { struct sockaddr_in client; socklen_t len=sizeof(client); //等待客户端的请求连接 int new_fd=accept(listen_sock,(struct sockaddr*)&client,&len); if(new_fd<0) { perror("accept"); continue; } printf("get a new client,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(\ client.sin_port)); pthread_t id; //创建线程 pthread_create(&id,NULL,handlerRequest,(void*)new_fd); //线程运行结束后释放资源 pthread_detach(id); }}
bind错误:
当服务器和客户端连接成功后,服务器不小心按下ctrl-c退出后,再次连接时,会显示一个bind错误,bind:Address already in use。原因: 该错误是由于TCP 套接字状态 TIME_WAIT 引起,TIME_WAIT状态在套接字关闭后约保留 2 到 4 分钟。当TIME_WAIT 状态退出之后,套接字被删除,此时该地址才能被重新绑定而不出问题。解决方法:①等待2~4分钟重新连接; ②给套接字应用 SO_REUSEADDR 套接字选项,以便端口可以马上重用 ③换一个端口使用;
如图所示:
阅读全文
0 0
- 多进程、多线程服务器程序
- 多进程、多线程服务器
- 用gdb调试多进程和多线程的服务器程序
- 使用 acl::master_threads 类编写多进程多线程服务器程序
- 实现多进程多线程服务器
- 多进程多线程TCP服务器
- socket--多进程,多线程服务器
- 多进程多线程服务器编写
- 开发多线程进程池服务器程序---acl 服务器框架应用
- TCP服务器多线程 多进程简单测试
- 多进程、多线程并发服务器代码
- 多进程多线程服务器(tcp_server)编写
- 多线程、多进程TCP服务器比较
- 多线程、多进程TCP服务器、进程池和线程池
- 多线程多进程服务器与进程线程池
- 多进程多线程TCP服务器以及进程池
- Python版单进程、多进程、多线程服务器
- gdb调试多进程和多线程程序
- 故障案例---innodb表出现大量的Waiting for table level lock
- windows10下安装tensorflow后无法使用的问题(一)
- Animation Set属性
- 什么是站点,Active Directory系列之十一
- listen EADDRINUSE :::3000 且 throw er; // Unhandled 'error' event
- 多进程、多线程服务器程序
- sping 配置文件的 路径 classpath
- Java+Selenium3方法篇20-浏览器退出quit和close的区别
- 锁
- WIN32工程加载一张BMP格式位图
- 如何查看Ubuntu的版本
- maven搭建项目,settings.xml配置文件,以及parent的pom.xml
- RTEMS-libbsd 实现beaglebone black USB驱动
- 实战Active Directory站点部署与管理,Active Directory系列之十二