一些观念:
同步和异步
同步和异步是针对应用措施和内核的交互而言的,同步指的是用户历程触发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;
}