Linux网络编程之循环服务器(其一)
创始人
2024-09-26 01:25:26
0

文章目录

  • 什么是循环服务器?
  • UDP循环服务器
    • 一个简单的UDP循环服务器代码
  • TCP循环服务器
    • 一个简单的TCP循环服务器代码
  • 附录(myhead.h)

本博客参考《Linux C/C++服务器开发实践》—— 朱文伟 李建英

什么是循环服务器?

循环服务器在同一个时刻只能响应一个客户端的请求,处理完一个客户端的工作后,才能处理下一个客户端的工作,就好像分时工作一样。循环服务器指的是对于客户端的请求和连接,服务器在处理完毕一个后,再处理另一个,即串行处理客户机的请求。这个I/O模型对应的是同步阻塞模型。
有关五种网络I/O模型的详细了解,请参考下面的博客:
链接:Linux网络编程之I/O模型(详解)

UDP循环服务器

UDP循环服务器的实现方法:UDP服务器每次从套接字上读取一个客户端的请求并处理,然后将处理结果返回给客户端。伪代码如下:

socket(); bind(); while(1){ 	recvfrom(); 	process(); 	sendto(); } 

因为UDP是无连接的,没有一个客户端可以一直占用服务器,服务器能满足每一个客户端的请求。

一个简单的UDP循环服务器代码

udpserver.cpp

#include "myhead.h"  #define PORT 10024 char rbuf[50], sbuf[100];  int main(){     int sockfd, size, ret, val;     char on = 1;     struct sockaddr_in saddr;     struct sockaddr_in raddr;      //设置地址信息,IP信息     size = sizeof(struct sockaddr_in);     val = sizeof(struct sockaddr);     memset(&saddr, 0, size);     saddr.sin_family = AF_INET;     saddr.sin_port = htons(PORT);     saddr.sin_addr.s_addr = htonl(INADDR_ANY);      //创建UDP套接字     sockfd = socket(AF_INET, SOCK_DGRAM, 0);     if(sockfd < 0){         perror("create sockfd fail\n");         return -1;     }      //设置端口复用     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));      //绑定地址信息     ret = bind(sockfd, (struct sockaddr*)&saddr, val);     if(ret < 0){         perror("bind fail\n");         return -1;     }      while(1){         puts("waitting data\n");         ret = recvfrom(sockfd, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&raddr,          (socklen_t*)&val);         if(ret < 0){             perror("recvfrom failed\n");         }          printf("recv data:%s\n", rbuf);         snprintf(sbuf, sizeof(sbuf), "server has received your data(%s)\n", rbuf);         ret = sendto(sockfd, sbuf, sizeof(rbuf), 0, (struct sockaddr*)&raddr,         val);          memset(rbuf, 0, sizeof(rbuf));     }     close(sockfd);     getchar();     return 0; } 

udpclient.cpp

#include  #include  #pragma comment(lib, "wsock32") #define BUF_SIZE 200 #define PORT 10024 #define IP "192.168.159.128" char wbuf[50], rbuf[100];  int main() {     SOCKET s;     int len = -1;     WSADATA wsadata;     struct hostent* phe;     struct servent* pse;     struct protoent* ppe;      struct sockaddr_in saddr, raddr;     int fromlen, ret, type;      if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) {         printf("WSAStarup failed\n");         return -1;     }     memset(&saddr, 0, sizeof(saddr));     saddr.sin_family = AF_INET;     saddr.sin_port = htons(PORT);     saddr.sin_addr.s_addr = inet_addr(IP);      if ((ppe = getprotobyname("UDP")) == 0) {         printf("get protocol information error \n");         WSACleanup();         return -1;     }      s = socket(PF_INET, SOCK_DGRAM, ppe->p_proto);     if (s == INVALID_SOCKET) {         printf(" create socket error \n");         WSACleanup();         return -1;     }     fromlen = sizeof(struct sockaddr);     printf("please inter data:");     scanf_s("%s", wbuf, sizeof(wbuf));     ret = sendto(s, wbuf, sizeof(wbuf), 0, (struct sockaddr*)&saddr, sizeof(struct sockaddr));      if (ret < 0) {         perror("sendto failed\n");     }     len = recvfrom(s, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&raddr, &fromlen);     if (len < 0) perror("recvfrom fail\n");     printf("server reply:%s\n", rbuf);      closesocket(s);     WSACleanup();     return 0; }   

注意,为了更贴近一线企业实战环境,客户端的程序是放到Windows上运行的,所以它的代码也使用了Windows系统提供的接口。该代码可以在Visual C++上运行,如果想深入了解Visual C++,可以参考清华大学出版社的《Viusal C++ 2017从入门到精通》一书。

TCP循环服务器

TCP服务器接受一个客户端的连接,然后处理,完成了这个客户端的所有请求后,断开连接。伪代码如下:

socket(); bind(); listen(); while(1){ 	accept(); 	process(); 	close(); } 

注:TCP循环服务器一次只能处理一个客户端的请求(除非使用一客户端一线程)。只有在这个客户端的所有请求都满足后,服务器才可以继续后面的请求。如果一个客户端占住服务器不放,则其他的客户端都不能工作,因此TCP服务器一般很少使用这个模型。
链接: 想了解更多服务器模型,可以参考这里

一个简单的TCP循环服务器代码

tcpserver.cpp

#include "myhead.h" #define  BUF_SIZE  200 #define PORT 8888  int main() { 	struct   sockaddr_in fsin; 	int       clisock,alen, connum = 0, len, s; 	char     buf[BUF_SIZE] = "hi,client", rbuf[BUF_SIZE]; 	struct  servent  *pse;    /* server information    */ 	struct  protoent *ppe;    /* proto information     */ 	struct sockaddr_in sin;   /* endpoint IP address   */  	memset(&sin, 0, sizeof(sin)); 	sin.sin_family = AF_INET; 	sin.sin_addr.s_addr = INADDR_ANY; 	sin.sin_port = htons(PORT);  	s = socket(PF_INET, SOCK_STREAM, 0); 	if (s == -1) 	{ 		printf("creat socket error \n"); 		getchar(); 		return -1; 	} 	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) 	{ 		printf("socket bind error \n"); 		getchar(); 		return -1; 	} 	if (listen(s, 10) == -1) 	{ 		printf("  socket listen error \n"); 		getchar(); 		return -1; 	} 	while (1) 	{ 		alen = sizeof(struct sockaddr); 		puts("waiting client..."); 		clisock = accept(s, (struct sockaddr *)&fsin,(socklen_t*)&alen); 		if (clisock == -1) 		{ 			printf("accept failed\n"); 			getchar(); 			return -1; 		} 		connum++; 		printf("%d  client  comes\n", connum); 		len = recv(clisock, rbuf, sizeof(rbuf), 0); 		if (len < 0) perror("recv failed"); 		sprintf(buf,"Server has received your data(%s).", rbuf); 		send(clisock, buf, strlen(buf), 0); 		close(clisock); 	} 	return 0; } 

tcpclient.cpp

#include "myhead.h" #define  BUF_SIZE  200 #define PORT 8888 char wbuf[50], rbuf[100]; int main() { 	char   buff[BUF_SIZE]; 	SOCKET  s; 	int    len; 	WSADATA  wsadata;  	struct hostent *phe;      /*host information     */ 	struct servent *pse;      /* server information  */ 	struct protoent *ppe;     /*protocol information */ 	struct sockaddr_in saddr;   /*endpoint IP address  */ 	int   type;  	if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) 	{ 		printf("WSAStartup failed\n"); 		WSACleanup(); 		return -1; 	} 	memset(&saddr, 0, sizeof(saddr)); 	saddr.sin_family = AF_INET; 	saddr.sin_port = htons(PORT); 	saddr.sin_addr.s_addr = inet_addr("192.168.0.153");   	s = socket(PF_INET, SOCK_STREAM, 0); 	if (s == INVALID_SOCKET) 	{ 		printf(" creat socket error \n"); 		WSACleanup(); 		return -1; 	} 	if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) == SOCKET_ERROR) 	{ 		printf("connect socket  error \n"); 		WSACleanup(); 		return -1; 	}   	printf("please enter data:"); 	scanf_s("%s", wbuf, sizeof(wbuf)); 	len = send(s, wbuf, sizeof(wbuf), 0); 	if (len < 0) perror("send failed"); 	len = recv(s, rbuf, sizeof(rbuf), 0); 	if (len < 0) perror("recv failed"); 	printf("server reply:%s\n", rbuf);   	closesocket(s); 	WSACleanup(); 	return 0; } 

都读到这了,免费给个三连支持一下吧,下一期我会继续努力~

附录(myhead.h)

// myhead.h #ifndef _MYHEAD_H #define _MYHEAD_H #include  #include  #include  #include  #include  #include  #include  #include  #include  #include   //跟输入子系统模型有关的头文件 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #endif  

相关内容

热门资讯

教程辅助“约战竞技场辅助脚本”... 教程辅助“约战竞技场辅助脚本”真的有挂开挂辅助下载解密教程;无需打开直接搜索打开薇:13670430...
透视安卓版“一起宁德钓蟹辅助”... 【亲,一起宁德钓蟹辅助 这款游戏可以开挂的,确实是有挂的,很多玩家在这款一起宁德钓蟹辅助中打牌都会发...
教程辅助“奇迹手游辅助脚本平台... 教程辅助“奇迹手游辅助脚本平台免费”有挂神器开挂辅助器AA德州教程!您好:奇迹手游辅助脚本平台免费这...
透视真的“安装胡乐辅助脚本”w... 大家好,今天小编来为大家解答安装胡乐辅助脚本这个问题咨询软件客服可以免费测试直接加微信(136704...
教程辅助“传送屋辅助k”有挂方... 教程辅助“传送屋辅助k”有挂方法开挂辅助脚本规律教程这是一款可以让一直输的玩家,快速成为一个“必胜”...
分享一款“拱趴辅助器”wepo... 分享一款“拱趴辅助器”wepoker私人局俱乐部怎么进(带开挂辅助软件AI教程);无需打开直接搜索加...
教程辅助“随意玩辅助器”有挂技... 教程辅助“随意玩辅助器”有挂技巧开挂辅助脚本专业教程1、下载安装好随意玩辅助器,进入游戏主界面,点击...
透视线上“牵手跑的快小程序技巧... 透视线上“牵手跑的快小程序技巧”wpk安卓下载辅助(带开挂辅助下载AI教程)您好:牵手跑的快小程序技...
教程辅助“阿拉斗牌辅助”有挂神... 教程辅助“阿拉斗牌辅助”有挂神器开挂辅助软件攻略方法;亲,阿拉斗牌辅助这款游戏原来确实可以开挂的,详...
透视科技“哥哥打大a有辅助吗”... 透视科技“哥哥打大a有辅助吗”德扑圈透视挂(带开挂辅助插件爆料教程)【无需打开直接搜索加薇13670...