并发服务器的实现方法:
- 多进程服务器
- 多路复用服务器
- 多线程服务器
select函数是I/O复用的全部内容,server端代码如下:
// echoSvrSelect.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment (lib,"ws2_32.lib")
#define BUF_SZ 1024
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket,hClientSock;
SOCKADDR_IN servAddr,clientAddr;
fd_set read_set, cpy_set;
int strlen,i,fd_num;
TIMEVAL timeout;
char message[BUF_SZ];
int szClientAddr;
if(argc!=2){
printf("usage : %s port\n",argv[0]);
return 0;
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
printf("WSAStartup failed\n");
return 0;
}
hSocket = socket(PF_INET,SOCK_STREAM,0);
if(hSocket == INVALID_SOCKET){
printf("socket error\n");
return 0;
}
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
if(bind(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR){
printf("bind port [%d] error\n",atoi(argv[1]));
return 0;
}
if(listen(hSocket,5) == SOCKET_ERROR){
printf("listen error\n");
return 0;
}
else{
printf("server started, port :%d\n",atoi(argv[1]));
}
FD_ZERO(&read_set);
FD_SET(hSocket,&read_set);
for(;;){
// select 的通用方法,selcet调用之后,除发生变化的文件描述符,其他的
// 所有位初始化为0,因此为了住初始值,必须经过这个复制过程
cpy_set = read_set;
// select 只有在监听的文件描述符变化时才返回,否则进入阻塞状态,
// 设置超时时间防止这种情况发生
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if((fd_num = select(0,&cpy_set,0,0,&timeout))==SOCKET_ERROR){
break;
}
if(fd_num == 0){
continue;
}
for(i=0;i<read_set.fd_count;++i){
if(FD_ISSET(read_set.fd_array[i],&cpy_set))
{
if(read_set.fd_array[i] == hSocket){
szClientAddr = sizeof(clientAddr);
hClientSock = accept(hSocket,(SOCKADDR*)&clientAddr,&szClientAddr);
FD_SET(hClientSock,&read_set);
char saddr[20];
char * paddr;
paddr = inet_ntoa(clientAddr.sin_addr);
strcpy(saddr,paddr);
printf("[%s:%d] connect!\n",saddr,ntohs(clientAddr.sin_port));
printf("total online:%d\n",read_set.fd_count);
}
else{
strlen=recv(read_set.fd_array[i],message,BUF_SZ-1,0);
message[strlen] = 0;
if(strlen == 0){
closesocket(read_set.fd_array[i]);
FD_CLR(read_set.fd_array[i],&read_set);
printf("close socket\n");
}
else{
printf("echo:%d:%s\n",read_set.fd_array[i],message);
send(read_set.fd_array[i],message,strlen,0);
}
}
}
}
}
closesocket(hSocket);
WSACleanup();
return 0;
}