一些观念:
同步和异步
同步和异步是针对应用措施和内核的交互而言的,同步指的是用户历程触发I/O操纵并期待可能轮询的去查察I/O操纵是否停当,而异步是指用户历程触发I/O操纵今后便开始做本身的工作,而当I/O操纵已经完成的时候会获得I/O完成的通知。
阻塞和非阻塞
阻塞和非阻塞是针对付历程在会见数据的时候,按照I/O操纵的停当状态来采纳的差异方法,说白了是一种读取可能写入操纵函数的实现方法,阻塞方法下读取可能写入函数将一直期待,而非阻塞方法下,读取可能写入函数会当即返回一个状态值。
处事器端几种模子:
1、阻塞式模子(blocking IO)
我们第一次打仗到的网络编程都是从 listen()、accpet()、send()、recv() 等接口开始的。利用这些接口可以很利便的构建C/S的模子。这里大部门的 socket 接口都是阻塞型的。所谓阻塞型接口是指系统挪用(一般是 IO 接口)不返回挪用功效并让当前线程一直阻塞,只有当该系统挪用得到功效可能超时堕落时才返回。
如下面一个简朴的Server端实现:
#include <Winsock2.h> #include <cstdio> #include <iostream> #include <string> using namespace std; #pragma comment(lib,"ws2_32.lib") int init_win_socket() { WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2) , &wsaData ) != 0) { return -1; } return 0; } #define Server_Port 10286 void handle_client(int newfd) { while(1) { char buff[1024]; memset(buff,0,1024); int result = recv(newfd,buff,1024,0); if(result <= 0) { break; } else { printf("Receive Data %s, Size: %d \n",buff,result); int ret = send(newfd,buff,result,0); if(ret>0) { printf("Send Data %s, Size: %d \n",buff,ret); } else { break; } } } closesocket(newfd); return; } int run() { int listener; struct sockaddr_in addr_server; listener = socket(AF_INET, SOCK_STREAM, 0); //addr_server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addr_server.sin_addr.S_un.S_addr = ADDR_ANY; addr_server.sin_family = AF_INET; addr_server.sin_port = htons(Server_Port); if(bind(listener,(const sockaddr *)&addr_server,sizeof(addr_server)) < 0) { perror("bind error"); return -1; } if (listen(listener, 10)<0) { perror("listen error"); return -1; } printf("Server is listening ... \n"); bool runing = true; while(runing) { sockaddr_in addr_client; int clientlen = sizeof(addr_client); int client_sock; if ((client_sock = accept(listener, (struct sockaddr *) &addr_client, &clientlen)) < 0) { printf("Failed to accept client connection \n"); } fprintf(stdout, "Client connected: %s \n", inet_ntoa(addr_client.sin_addr)); /*Handle this connect */ handle_client(client_sock); } closesocket(listener); return 0; } int main(int c, char **v) { #ifdef WIN32 init_win_socket(); #endif run(); getchar(); return 0; }
示意图如下:
这里的socket的接口是阻塞的(blocking),在线程被阻塞期间,线程将无法执行任何运算或响应任何的网络请求,这给多客户机、多业务逻辑的网络编程带来了挑战。
2、多线程的处事器模子(Multi-Thread)
应对多客户机的网络应用,最简朴的办理方法是在处事器端利用多线程(或多历程)。多线程(或多历程)的目标是让每个毗连都拥有独立的线程(或历程),这样任何一个毗连的阻塞都不会影响其他的毗连。
多线程Server端的实现:
#include <Winsock2.h> #include <cstdio> #include <iostream> #include <string> using namespace std; #pragma comment(lib,"ws2_32.lib") int init_win_socket() { WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2) , &wsaData ) != 0) { return -1; } return 0; } #define Server_Port 10286 DWORD WINAPI handle_client(LPVOID lppara) { int *newfd = (int *)lppara; while(1) { char buff[1024]; memset(buff,0,1024); int result = recv(*newfd,buff,1024,0); if(result <= 0) { break; } else { printf("Receive Data %s, Size: %d \n",buff,result); int ret = send(*newfd,buff,result,0); if(ret>0) { printf("Send Data %s, Size: %d \n",buff,ret); } else { break; } } Sleep(10); } closesocket(*newfd); return 0; } int run() { int listener; struct sockaddr_in addr_server; int sock_clients[1024]; //max number for accept client connection; listener = socket(AF_INET, SOCK_STREAM, 0); //addr_server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addr_server.sin_addr.S_un.S_addr = ADDR_ANY; addr_server.sin_family = AF_INET; addr_server.sin_port = htons(Server_Port); if(bind(listener,(const sockaddr *)&addr_server,sizeof(addr_server)) < 0) { perror("bind error"); return -1; } if (listen(listener, 10)<0) { perror("listen error"); return -1; } printf("Server is listening ... \n"); int fd_count = 0; bool runing = true; while(runing) { sockaddr_in addr_client; int clientlen = sizeof(addr_client); int client_sock; if ((client_sock = accept(listener, (struct sockaddr *) &addr_client, &clientlen)) < 0) { printf("Failed to accept client connection \n"); } fprintf(stdout, "Client connected: socket fd %d , %s \n", client_sock,inet_ntoa(addr_client.sin_addr)); /*Handle this connect */ if(fd_count<1024) { sock_clients[fd_count] = client_sock; if(CreateThread(NULL,0,handle_client,&sock_clients[fd_count],0,NULL)==NULL) return -1; ++ fd_count; } Sleep(10); } closesocket(listener); return 0; } int main(int c, char **v) { #ifdef WIN32 init_win_socket(); #endif run(); getchar(); return 0; }