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

标签: 迭代服务器
661人阅读 评论(0) 收藏 举报
本文章已收录于:
分类:

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

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


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

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

二、UDP 迭代服务器

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

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

udp迭代服务器框架:

  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. }  
//1.创建套接字
int sockfd = socket(...);

//2.绑定套接字
bind(...);

while(1)
{
	//3.接收客户端的请求
	recvfrom(...);
	
	//4.处理客户端的请求
	process(...);
	
	//5.反馈处理结果
	sendto(...);
}

udp迭代服务器参考代码:

  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. }  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	unsigned short port = 8080;	//本地端口

	//1.创建udp套接字
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	// 配置本地网络信息
	struct sockaddr_in my_addr;
	bzero(&my_addr, sizeof(my_addr));	// 清空
	my_addr.sin_family = AF_INET;		// IPv4
	my_addr.sin_port   = htons(port);	// 端口
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip
	
	printf("Binding server to port %d\n", port);
	
	// 2.绑定套接字
	int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if(err_log != 0)
	{
		perror("bind");
		close(sockfd);		
		exit(-1);
	}
	
	printf("receive data...\n");
	while(1)
	{
		int recv_len;
		char recv_buf[512] = {0};
		struct sockaddr_in client_addr;
		char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16
		socklen_t cliaddr_len = sizeof(client_addr);
		
		//3.接收客户端的请求
		recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);
		
		//4.处理客户端的请求,这里只是把接收过来的数据打印
		inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
		printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port)); // 客户端的ip
		printf("data(%d):%s\n",recv_len,recv_buf);	// 客户端的数据
		
		//5.反馈处理结果,这里把接收直接到客户端的数据回复过去
		sendto(sockfd, recv_buf, recv_len, 0, (struct sockaddr*)&client_addr, cliaddr_len);
	}
	
	close(sockfd);
	
	return 0;
}

运行结果:



三、tcp迭代服务器

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

tcp迭代服务器框架:

  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);  
//1.创建tcp套接字
int sockfd = socket(...);

//2.绑定套接字
bind(...);

//3.监听套接字
listen(...);

while(1)
{
	//4.提取已连接套接字
	int connfd = accept(...);
	
	//5.处理客户端的请求
	process(...);
	
	//6.关闭已连接套接字
	close(connfd);
}

//7.关闭监听套接字
close(sockfd);

tcp迭代服务器参考代码:

  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. }  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>						
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
			
int main(int argc, char *argv[])
{
	unsigned short port = 8080;		// 本地端口	

	//1.创建tcp套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);   
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	//配置本地网络信息
	struct sockaddr_in my_addr;
	bzero(&my_addr, sizeof(my_addr));	  // 清空   
	my_addr.sin_family = AF_INET;		  // IPv4
	my_addr.sin_port   = htons(port);	  // 端口
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip
	
	//2.绑定
	int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if( err_log != 0)
	{
		perror("binding");
		close(sockfd);		
		exit(-1);
	}
	
	//3.监听,套接字变被动
	err_log = listen(sockfd, 10); 
	if(err_log != 0)
	{
		perror("listen");
		close(sockfd);		
		exit(-1);
	}	
	
	printf("listen client @port=%d...\n",port);

	while(1)
	{	
	
		struct sockaddr_in client_addr;		   
		char cli_ip[INET_ADDRSTRLEN] = "";	   
		socklen_t cliaddr_len = sizeof(client_addr);    
		
		//4.取出客户端已完成的连接
		int connfd;
		connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);       
		if(connfd < 0)
		{
			perror("accept");
			continue;
		}

		//5.打印客户端的ip和端口
		inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
		printf("----------------------------------------------\n");
		printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));
		
		// 接收数据
		char recv_buf[512] = {0};
		int len =  recv(connfd, recv_buf, sizeof(recv_buf), 0);
		
		// 处理数据,这里只是打印接收到的内容
		printf("\nrecv data:\n");
		printf("%s\n",recv_buf);
		
		// 反馈结果
		send(connfd, recv_buf, len, 0);
		
		//6.关闭已连接套接字
		close(connfd);     
		printf("client closed!\n");
	}
	
	//7.关闭监听套接字
	close(sockfd);         
	
	return 0;
}

运行结果:


2
2
 
 
我的同类文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值