1、函数原型及头文件
- windows下头文件为#include<WinSock2.h>
- linux下头文件为
#include<unistd.h>#include<sys/time.h>
- 原型
int select(int nfds,fd_set *readsets,fd_set *writesets,fd_set *exceptsets,const struct timeval *timeout)返回值:就绪描述符的数目,超时返回0,出错返回-1
2、实测代码
着重要注意的点是:每次select结束后描述符的值会发生变化,所以每次循环开始要将read_fds和write_fds全部清理,然后将socketid重新fdset。
服务器端代码如下
服务器端代码如下
#include <stdio.h>
#include <string>
#include <vector>
#ifdef WINDOWS
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#endif
#ifdef LINUX
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#endif
#pragma warning(disable:4996)
#define DEFAULT_PORT 48000
#define MAXLEN 4096
void prepareIDs(int listen_fd,std::vector<int> accept_fd,int &max_fd,fd_set &read_fds,fd_set &write_fds)
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(listen_fd, &read_fds);
max_fd = listen_fd;
for (auto itor = accept_fd.begin(); itor != accept_fd.end(); itor++)
{
FD_SET(*itor, &read_fds);
FD_SET(*itor, &write_fds);
max_fd = max(max_fd, *itor);
}
max_fd += 1;
}
void doReadActions(int fd)
{
char buff[4096];
memset(buff, 0, sizeof(buff));
int len = recv(fd, buff, MAXLEN, 0);
printf("Receive buffer[%s]\n", buff);
}
void doWriteActions(int fd)
{
char *buff = "This is the message sending from HOST.";
send(fd, buff, strlen(buff)+1, 0);
//printf("Host send message ok\n");
}
int main()
{
int listen_fd;
struct sockaddr_in servaddr;
fd_set readfds, writefds;
std::vector<int> accept_fds;
int max_fd;
timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 500000;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
WSADATA initData;
if (WSAStartup(MAKEWORD(2, 2), &initData)) {
printf("Can not init socket");
return -1;
}
if ((listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(DEFAULT_PORT);
if (bind(listen_fd,(struct sockaddr*)&servaddr,sizeof(servaddr))== -1){
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
closesocket(listen_fd);
exit(0);
}
if (listen(listen_fd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
closesocket(listen_fd);
exit(0);
}
accept_fds.clear();
while (1)
{
prepareIDs(listen_fd, accept_fds, max_fd, readfds, writefds);
//printf("r1: readfds.fd_count[%d],writefds.fd_count[%d]\n", readfds.fd_count, writefds.fd_count);
int rtn = select(max_fd, &readfds, &writefds, 0, &timeout);
//printf("r2: readfds.fd_count[%d],writefds.fd_count[%d]\n", readfds.fd_count, writefds.fd_count);
if (FD_ISSET(listen_fd, &readfds))//如果listen_fd有值,代表有新的链接,存入新的socketid
{
int new_socket = accept(listen_fd, (struct sockaddr*)NULL,NULL);
printf("receive client accept\n");
if (new_socket<0)
{
printf("accept socket error: %s(errno: %d)", strerror(errno), errno);
continue;
}
accept_fds.push_back(new_socket);
}
for (auto itor = accept_fds.begin(); itor != accept_fds.end(); itor++)
{
if (FD_ISSET(*itor, &readfds))
doReadActions(*itor);
if (FD_ISSET(*itor, &writefds))
doWriteActions(*itor);
}
}
return 0;
}
客户端代码如下:
#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#pragma message("error!!!")
#define DefaultPort 48000
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(DefaultPort);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
send(sockClient,"This is test",strlen("This is test")+1,0);
char recvBuf[100];
memset(recvBuf,0,sizeof(recvBuf));
while(recv(sockClient,recvBuf,100,0)>0)
{
printf("%s\n",recvBuf);
}
//recv(sockClient,recvBuf,100,0);
//printf("%s\n",recvBuf);
closesocket(sockClient);
WSACleanup();
}