阅读量:0
文章目录
本博客参考《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 <stdio.h> #include <winsock.h> #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 <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/mman.h> #include <linux/input.h> //跟输入子系统模型有关的头文件 #include <dirent.h> #include <stdbool.h> #include <strings.h> #include <sys/wait.h> #include <signal.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #include <sys/sem.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <netdb.h> #include <poll.h> #include <sys/epoll.h> #endif