linux下 socket tcp Server c语言编写(分别实现单进程,多进程,多线程)

xiaoxiao2021-02-28  81

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_ 10 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; 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_ 10 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; 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_ 10 void *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 9999 int 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; }
转载请注明原文地址: https://www.6miu.com/read-39725.html

最新回复(0)