linux下 socket tcp Server c语言编写(分别实现单进程,多进程,多线程)
来源:互联网 发布:网络接单平台 编辑:程序博客网 时间:2024/06/06 10:53
TCP 迭代服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。TCP 迭代服务器一次只能处理一个客户端的请求,只有在这个客户的所有请求满足后,服务器才可以继续后面的请求。如果有一个客户端占住服务器不放时,其它的客户机都不能工作了,因此,TCP 服务器一般很少用迭代服务器模型的。
tcp服务器端框架
1.创建tcp套接字
2. 绑定套接字
3. 监听套接字
4. 调用accept()阻塞等待
5. 处理客户端的请求
6. 关闭连接套接字
7. 关闭监听套接字
tcp客户端框架
1.创建tcp套接字
2.调用connect()连接服务器
3.处理服务器端返回的信息
由于客户端不需要固定的端⼜号,因此不必调⽤bind(),客户端的端⼜号由内核⾃动分配。注意, 客户端不是不允许调⽤bind(),只是没有必要调⽤bind()固定⼀个端⼜号,服务器也不是必须调⽤bind(),但如果服务器不调⽤bind(),内核会⾃动给服务器分配监听端⼜,每次启动服务器时端⼜ 号都不⼀样,客户端要连接服务器就会遇到⿇烦。
单进程
server.c
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<errno.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#include<arpa/inet.h>#include<netinet/in.h>#define _PORT_ 9999#define _BACKLOG_ 10int main(){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { printf("socket()\n"); } struct sockaddr_in server_socket; struct sockaddr_in socket; bzero(&server_socket,sizeof(server_socket)); server_socket.sin_family=AF_INET; server_socket.sin_addr.s_addr=htonl(INADDR_ANY); server_socket.sin_port=htons(_PORT_); if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0) { printf("bind()\n"); close(sock); return 1; } if(listen(sock,_BACKLOG_)<0) { printf("listen()\n"); close(sock); return 2; } printf("success\n"); for(;;) { socklen_t len=0; int client_sock=accept(sock,(struct sockaddr*)&socket,&len); if(client_sock<0) { printf("accept()\n"); return 3; } char buf_ip[INET_ADDRSTRLEN]; memset(buf_ip,'\0',sizeof(buf_ip)); inet_ntop(AF_INET,&socket.sin_addr,buf_ip,sizeof(buf_ip)); printf("get connect\n"); while(1) { char buf[1024]; memset(buf,'\0',sizeof(buf)); read(client_sock,buf,sizeof(buf)); printf("client:# %s\n",buf); printf("server:$ "); memset(buf,'\0',sizeof(buf)); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]='\0'; if(strncasecmp(buf,"quit",4)==0) { printf("quit\n"); break; } write(client_sock,buf,strlen(buf)+1); printf("wait...\n"); } close(client_sock); } close(sock); return 0;}
多进程
怎么将单进程的代码改为多进程的代码呢?
调用fork()函数,创建子进程,将所有的客户端的请求处理的内容都放在子进程中处理。
在 Linux 环境下多进程的应用很多,其中最主要的就是网络/客户服务器。多进程服务器是当客户有请求时,服务器用一个子进程来处理客户请求。父进程继续等待其它客户的请求。这种方法的优点是当客户有请求时,服务器能及时处理客户,特别是在客户服务器交互系统中。对于一个 TCP 服务器,客户与服务器的连接可能并不马上关闭,可能会等到客户提交某些数据后再关闭,这段时间服务器端的进程会阻塞,所以这时操作系统可能调度其它客户服务进程,这比起循环服务器大大提高了服务性能。
server.c
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<errno.h>#include<unistd.h>#include<string.h>#include<sys/types.h> #include<arpa/inet.h>#include<netinet/in.h>#define _PORT_ 9999#define _BACKLOG_ 10int main(){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { printf("socket()\n"); } struct sockaddr_in server_socket; struct sockaddr_in socket; bzero(&server_socket,sizeof(server_socket)); server_socket.sin_family=AF_INET; server_socket.sin_addr.s_addr=htonl(INADDR_ANY); server_socket.sin_port=htons(_PORT_); if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0) { printf("bind()\n"); close(sock); return 1; } if(listen(sock,_BACKLOG_)<0) { printf("listen()\n"); close(sock); return 2; } printf("success\n"); for(;;) { socklen_t len=0; int client_sock=accept(sock,(struct sockaddr*)&socket,&len); if(client_sock<0) { printf("accept()\n"); return 3; } char buf_ip[INET_ADDRSTRLEN]; memset(buf_ip,'\0',sizeof(buf_ip)); inet_ntop(AF_INET,&socket.sin_addr,buf_ip,sizeof(buf_ip)); printf("get connect\n"); pid_t fd=fork(); if(fd<0) printf("fork()\n"); if(fd==0) { close(sock);//关闭监听套接字 printf("port=%d,ip=%s\n",ntohs(socket.sin_port),buf_ip); while(1) { char buf[1024]; memset(buf,'\0',sizeof(buf)); read(client_sock,buf,sizeof(buf)); printf("client:# %s\n",buf); printf("server:$ "); memset(buf,'\0',sizeof(buf)); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]='\0'; if(strncasecmp(buf,"quit",4)==0) { printf("quit\n"); break; } write(client_sock,buf,strlen(buf)+1); printf("wait...\n"); } close(fd); } else if(fd>0) { close(fd); } } close(sock); return 0;}
多线程
多线程和多进程的处理方式类似,都是创建一个新的线程,客户端有请求时,用新创建的线程处理。
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<errno.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#include<arpa/inet.h>#include<netinet/in.h>#define _PORT_ 9999#define _BACKLOG_ 10void *fun(void* arg){ int client_sock = (int)arg; while(1) { char buf[1024]; memset(buf,'\0',sizeof(buf)); read(client_sock,buf,sizeof(buf)); printf("client:# %s\n",buf); printf("server:$ "); memset(buf,'\0',sizeof(buf)); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]='\0'; if(strncasecmp(buf,"quit",4)==0) { printf("quit\n"); break; } write(client_sock,buf,strlen(buf)+1); printf("wait...\n"); } close(client_sock);}int main(){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { printf("socket()\n"); } struct sockaddr_in server_socket; struct sockaddr_in socket; pthread_t thread_id; bzero(&server_socket,sizeof(server_socket)); server_socket.sin_family=AF_INET; server_socket.sin_addr.s_addr=htonl(INADDR_ANY); server_socket.sin_port=htons(_PORT_); if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0) { printf("bind()\n"); close(sock); return 1; } if(listen(sock,_BACKLOG_)<0) { printf("listen()\n"); close(sock); return 2; } printf("success\n"); for(;;) { socklen_t len=0; int client_sock=accept(sock,(struct sockaddr*)&socket,&len); if(client_sock<0) { printf("accept()\n"); return 3; } char buf_ip[INET_ADDRSTRLEN]; memset(buf_ip,'\0',sizeof(buf_ip)); inet_ntop(AF_INET,&socket.sin_add,buf_ip,sizeof(buf_ip)); printf("get connect,ip is%s\n",buf_ip); printf("port=%d\n",ntohs(socket.sin_port)); pthread_create(&thread_id, NULL, (void *)fun, (void *)client_sock); pthread_detach(thread_id); } close(sock); return 0;}
不管是哪一种的服务器,客户端都是一样的
client.c
#include<stdio.h>#include<unistd.h>#include<sys/socket.h>#include<string.h>#include<errno.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/types.h>#define SERVER_PORT 9999int main(int argc,char* argv[]){ if(argc!=2) { printf("Usage:client IP\n"); return 1; } char *str=argv[1]; char buf[1024]; memset(buf,'\0',sizeof(buf));struct sockaddr_in server_sock; int sock = socket(AF_INET,SOCK_STREAM,0); bzero(&server_sock,sizeof(server_sock)); server_sock.sin_family=AF_INET; inet_pton(AF_INET,str,&server_sock.sin_addr); server_sock.sin_port=htons(SERVER_PORT); int ret=connect(sock,(struct sockaddr *)&server_sock,sizeof(server_sock)); if(ret<0) { printf("connect()\n"); return 1; } printf("connect success\n"); while(1) { printf("client:# "); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]='\0'; write(sock,buf,sizeof(buf)); if(strncasecmp(buf,"quit",4)==0) { printf("quit\n"); break; } printf("wait..\n"); read(sock,buf,sizeof(buf)); printf("server:$ %s\n",buf); } close(sock); return 0;}
- linux下 socket tcp Server c语言编写(分别实现单进程,多进程,多线程)
- linux socket tcp Server c语言编写
- Linux下C语言多进程实现
- Linux TCP server系列(5)-select模式下的单进程server
- Linux C语言编程-Linux网络通信--Linux上使用套接字(socket)来处理信息---编写一个单进程非阻塞多客户的套接字客户端
- TCP server的实现,和多线程,多进程服务器
- C语言编写linux下的守护进程
- linux下使用C语言编写管理进程
- Linux下TCP多进程/多线程套接字通信
- Linux守护进程实现 (C语言)
- Linux下多进程编程(C语言)
- Linux下套接字详解(八)----select模式下服务器(非阻塞,单进程+多进程+多线程)
- socket套接字编写多线程多进程的server和client
- 使用 异步多线程TCP Socket 实现进程间通信
- unix/linux socket 编程一,简单多进程tcp socket server流程
- Linux下C语言实现查看进程是否存在
- Linux下C语言实现查看进程是否存在
- Linux下C语言实现查看进程是否存在
- Codeforces E.Bindian Signalizing
- CSS hack原理与常见的hack
- 士兵杀敌(二)
- MongoDB mapreduce 使用
- 二叉树的C++实现
- linux下 socket tcp Server c语言编写(分别实现单进程,多进程,多线程)
- [USACO3.3]骑马修栅栏 Riding the Fences
- adb查看SharedPreferences出现Permission denied不root解决方法
- 深入理解react-redux
- POI excel 设置样式
- 关于junit断言
- 软件系统概要设计的三大要素
- 将两个并列的元素的属性设为inline-block的影响
- 485. Max Consecutive Ones