日期:2014-05-16  浏览次数:20706 次

Linux下用select()实现异步的Echo服务器

本例子使用异步socket(select方法)实现了ECHO服务器程序。

搞了一个晚上,终于弄好了,出现的问题主要如下:

  • 这是最重要的问题!当读取完数据后,需要将数据重新FD_SET进去,特别是serverFd,注意这个testFd意义非常重大,相当于参数传递中的复制行参,需要好好体会。
  • 当read(rd)后,返回为0表示客户端的socket已经关闭,此时除了要FD_CLR,还要关闭fd!!否则fd资源没有被释放,很快就会达到select监听的上限!

#相关代码, [四号程序员] http://www.coder4.com
/*
?* main.cc
?*
?* ?Created on: 2009-11-30
?* ? ? ?Author: liheyuan
?* ? ?Describe: 非阻塞模式服务器(Echo服务器)
?*
?* ? Last Date: 2009-11-30
?* ? CopyRight: 2009 @ ICT LiHeyuan
?*/
?
#include <iostream>
using namespace std;
?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
?
#define SERVER_PORT 18000
?
#define SERVER_QUEUE 10
#define FD_SET_SIZE 10
#define MAX_BUF 16
?
int main() {
?
?? ?//设置服务器Addr,在18000,任意IP监听
?? ?int serverFd;
?? ?serverFd = socket(AF_INET, SOCK_STREAM, 0);
?
?? ?/* 设置 serverFd 为非阻塞方式 */
?? ?int opt = SO_REUSEADDR;
?? ?setsockopt(serverFd, SOL_SOCKET, opt, &opt, sizeof(opt));
?
?? ?struct sockaddr_in serverAddr;
?? ?socklen_t serverAddrLen = sizeof(sockaddr_in);
?? ?serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
?? ?serverAddr.sin_port = htons(SERVER_PORT);
?
?? ?//绑定
?? ?if (bind(serverFd, (sockaddr*) &serverAddr, serverAddrLen)) {
?? ? ? ?cout << "Binding on " << SERVER_PORT << " fail." << endl;
?? ? ? ?return -1;
?? ?}
?
?? ?//创建等待队列
?? ?listen(serverFd, SERVER_QUEUE);
?
?? ?//设定fd_set
?? ?fd_set readfds, testfds;
?? ?FD_ZERO(&readfds);
?? ?FD_SET(serverFd,&readfds);
?
?? ?//非阻塞模式等待客户连接
?? ?struct sockaddr_in clientAddr;
?? ?int clientFd;
?? ?socklen_t clientAddrLen;
?? ?int len;
?? ?char buf[MAX_BUF];
?? ?while (1) {
?? ? ? ?FD_SET(serverFd,&readfds);
?? ? ? ?testfds = readfds;
?
?? ? ? ?//选择readfds中可用的fd
?? ? ? ?if (select(FD_SET_SIZE, &testfds, (fd_set *) NULL, (fd_set *) NULL,
?? ? ? ? ? ? ? ?(struct timeval *) NULL) > 0) {
?? ? ? ? ? ?if (FD_ISSET(serverFd,&testfds)) {
?? ? ? ? ? ? ? ?//如果服务器fd可用,则为accept
?? ? ? ? ? ? ? ?clientAddrLen = sizeof(sockaddr_in);
?? ? ? ? ? ? ? ?clientFd =