Linux网络编程——tcp、udp迭代服务器

时间:2021-07-07 17:47:30

一、迭代与并发服务器概述

服务器设计技术有很多,按使用的协议来分有 TCP 服务器和 UDP 服务器,按处理方式来分有迭代服务器(循环服务器)和并发服务器


在网络程序里面,一般来说都是许多客户对应一个服务器(多对一),为了处理客户的请求,对服务端的程序就提出了特殊的要求。

目前最常用的服务器模型有:
迭代服务器:服务器在同一时刻只能响应一个客户端的请求
并发服务器:服务器在同一时刻可以响应多个客户端的请求

二、UDP 迭代服务器

UDP 循环服务器每次从套接字上读取一个客户端的请求 -> 处理 -> 然后将结果返回给客户机。

因为 UDP 是非面向连接的,没有一个客户端可以老是占住服务端。只要处理过程不是死循环,或者耗时不是很长,服务器对于每一个客户机的请求在某种程度上来说是能够满足。

udp迭代服务器框架:

[csharp] view plain copy
  1. //1.创建套接字  
  2. int sockfd = socket(...);  
  3.   
  4. //2.绑定套接字  
  5. bind(...);  
  6.   
  7. while(1)  
  8. {  
  9.     //3.接收客户端的请求  
  10.     recvfrom(...);  
  11.       
  12.     //4.处理客户端的请求  
  13.     process(...);  
  14.       
  15.     //5.反馈处理结果  
  16.     sendto(...);  
  17. }  

udp迭代服务器参考代码:

[csharp] view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <unistd.h>  
  5. #include <sys/socket.h>  
  6. #include <netinet/in.h>  
  7. #include <arpa/inet.h>  
  8.   
  9. int main(int argc, char *argv[])  
  10. {  
  11.     unsigned short port = 8080; //本地端口  
  12.   
  13.     //1.创建udp套接字  
  14.     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);   
  15.     if(sockfd < 0)  
  16.     {  
  17.         perror("socket");  
  18.         exit(-1);  
  19.     }  
  20.       
  21.     // 配置本地网络信息  
  22.     struct sockaddr_in my_addr;  
  23.     bzero(&my_addr, sizeof(my_addr));   // 清空  
  24.     my_addr.sin_family = AF_INET;       // IPv4  
  25.     my_addr.sin_port   = htons(port);   // 端口  
  26.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip  
  27.       
  28.     printf("Binding server to port %d\n", port);  
  29.       
  30.     // 2.绑定套接字  
  31.     int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));  
  32.     if(err_log != 0)  
  33.     {  
  34.         perror("bind");  
  35.         close(sockfd);        
  36.         exit(-1);  
  37.     }  
  38.       
  39.     printf("receive data...\n");  
  40.     while(1)  
  41.     {  
  42.         int recv_len;  
  43.         char recv_buf[512] = {0};  
  44.         struct sockaddr_in client_addr;  
  45.         char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16  
  46.         socklen_t cliaddr_len = sizeof(client_addr);  
  47.           
  48.         //3.接收客户端的请求  
  49.         recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);  
  50.           
  51.         //4.处理客户端的请求,这里只是把接收过来的数据打印  
  52.         inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);  
  53.         printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port)); // 客户端的ip  
  54.         printf("data(%d):%s\n",recv_len,recv_buf);  // 客户端的数据  
  55.           
  56.         //5.反馈处理结果,这里把接收直接到客户端的数据回复过去  
  57.         sendto(sockfd, recv_buf, recv_len, 0, (struct sockaddr*)&client_addr, cliaddr_len);  
  58.     }  
  59.       
  60.     close(sockfd);  
  61.       
  62.     return 0;  
  63. }  

运行结果:
Linux网络编程——tcp、udp迭代服务器


三、tcp迭代服务器

TCP 迭代服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。TCP 迭代服务器一次只能处理一个客户端的请求,只有在这个客户的所有请求满足后,服务器才可以继续后面的请求。如果有一个客户端占住服务器不放时,其它的客户机都不能工作了,因此,TCP 服务器一般很少用迭代服务器模型的。

tcp迭代服务器框架:

[csharp] view plain copy
  1. //1.创建tcp套接字  
  2. int sockfd = socket(...);  
  3.   
  4. //2.绑定套接字  
  5. bind(...);  
  6.   
  7. //3.监听套接字  
  8. listen(...);  
  9.   
  10. while(1)  
  11. {  
  12.     //4.提取已连接套接字  
  13.     int connfd = accept(...);  
  14.       
  15.     //5.处理客户端的请求  
  16.     process(...);  
  17.       
  18.     //6.关闭已连接套接字  
  19.     close(connfd);  
  20. }  
  21.   
  22. //7.关闭监听套接字  
  23. close(sockfd);  

tcp迭代服务器参考代码:

[csharp] view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>                         
  4. #include <unistd.h>  
  5. #include <sys/socket.h>  
  6. #include <netinet/in.h>  
  7. #include <arpa/inet.h>  
  8.               
  9. int main(int argc, char *argv[])  
  10. {  
  11.     unsigned short port = 8080;     // 本地端口   
  12.   
  13.     //1.创建tcp套接字  
  14.     int sockfd = socket(AF_INET, SOCK_STREAM, 0);     
  15.     if(sockfd < 0)  
  16.     {  
  17.         perror("socket");  
  18.         exit(-1);  
  19.     }  
  20.       
  21.     //配置本地网络信息  
  22.     struct sockaddr_in my_addr;  
  23.     bzero(&my_addr, sizeof(my_addr));     // 清空     
  24.     my_addr.sin_family = AF_INET;         // IPv4  
  25.     my_addr.sin_port   = htons(port);     // 端口  
  26.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip  
  27.       
  28.     //2.绑定  
  29.     int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));  
  30.     if( err_log != 0)  
  31.     {  
  32.         perror("binding");  
  33.         close(sockfd);        
  34.         exit(-1);  
  35.     }  
  36.       
  37.     //3.监听,套接字变被动  
  38.     err_log = listen(sockfd, 10);   
  39.     if(err_log != 0)  
  40.     {  
  41.         perror("listen");  
  42.         close(sockfd);        
  43.         exit(-1);  
  44.     }     
  45.       
  46.     printf("listen client @port=%d...\n",port);  
  47.   
  48.     while(1)  
  49.     {     
  50.       
  51.         struct sockaddr_in client_addr;          
  52.         char cli_ip[INET_ADDRSTRLEN] = "";       
  53.         socklen_t cliaddr_len = sizeof(client_addr);      
  54.           
  55.         //4.取出客户端已完成的连接  
  56.         int connfd;  
  57.         connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);         
  58.         if(connfd < 0)  
  59.         {  
  60.             perror("accept");  
  61.             continue;  
  62.         }  
  63.   
  64.         //5.打印客户端的ip和端口  
  65.         inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);  
  66.         printf("----------------------------------------------\n");  
  67.         printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));  
  68.           
  69.         // 接收数据  
  70.         char recv_buf[512] = {0};  
  71.         int len =  recv(connfd, recv_buf, sizeof(recv_buf), 0);  
  72.           
  73.         // 处理数据,这里只是打印接收到的内容  
  74.         printf("\nrecv data:\n");  
  75.         printf("%s\n",recv_buf);  
  76.           
  77.         // 反馈结果  
  78.         send(connfd, recv_buf, len, 0);  
  79.           
  80.         //6.关闭已连接套接字  
  81.         close(connfd);       
  82.         printf("client closed!\n");  
  83.     }  
  84.       
  85.     //7.关闭监听套接字  
  86.     close(sockfd);           
  87.       
  88.     return 0;  
  89. }  

运行结果:
Linux网络编程——tcp、udp迭代服务器