2010-11-10 19:56:00 hustxyj 阅读数 1071

最近在写一个Linux下的多线程的网络聊天软件,以前一直都是来一个连接开一个线程去recv,最近刚看了select函数的用法,就把select封成了一个类,外界只要创建一个该类的对象,然后把socket注册进来就可以。

本人新手,如果有什么问题或者bug或者可以改进的地方请各位多指教!!

 

初始化后开一个线程select,同时监听一个udp端口,用于注册socket或注销socket时主线程通知select的线程。

加锁和端口管理未实现…………

 

 

/** hpp文件 */


#ifndef SOCKETNOTIFIER_HPP_

#define SOCKETNOTIFIER_HPP_


#include <map>

#include <set>

#include <pthread.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>


/** CSocketNotifier socket通知类

 *

 *  总管socket的通知,对select作一层封装

 */


class CSocketNotifier

{

public:


    /** 回调函数 */

    typedef bool ( *sockCallBack )( void* );


    typedef struct tagSockParam

    {

        int sock_fd;

        void* pUsr;

    }SOCKPARAM;


    /** 构造函数

     *

     *  该函数为该类的构造函数,在创建该类对象时自动调用

     */

    CSocketNotifier();


    /** 析构函数

     *

     *  该函数执行该类的析构操作,在销毁该类对象时自动调用

     */

    ~CSocketNotifier();


    /** 获取空闲的端口

     *

     *  获取一个当前未使用的端口

     *  @return:  unsigned short

     */

    unsigned short getFreePort();


    /** 注册socket

     *

     *  把一个socket注册到类中

     *  @param:  int sock_fd

     *  @param:  sockCallBack pFun

     *  @param:  void * pParam

     *  @return:  bool

     */

    bool registerSocket( int sock_fd, sockCallBack pFun, void* pParam );


    /** 注销socket

     *

     *  把一个socket从类中注销

     *  @param:  int sock_fd

     *  @return:  bool

     */

    bool unregisterSocket( int sock_fd );


    /** 等待时间的发生

     *

     *  用select函数等待

     *  @param:  void *

     *  @return:  void*

     */

    static void* waitForEvent( void * );


    /** 更新socket集合

     *

     *  更新socket集合

     *  @param:  const std::set<int> &fdVec

     *  @return:  void*

     */

    static bool renewFD( int event_fd, std::set<int> &fdSet, fd_set *pre_fdsr, int &iMaxFD );


    /** 事件发生后通知

     *

     *  遍历所有注册进来的socket,通知

     *  @param:  int iEventNum

     *  @return:  bool

     */

    bool notify( fd_set* pfdsr, int iEventNum ); 


private:


    /** 通知线程socket变化

     *

     *  通知线程socket变化

     *  @param:  int sock_fd

     *  @return:  bool

     */

    bool sendNoticeToThread( int sock_fd );



private:

    /** 回调函数集合,int对应socket句柄,sockCallBack对应函数,void*对应参数 */

    std::map< int, std::pair < sockCallBack, void* > > m_aFun;


    pthread_t m_threadID;


    /** 停止时退出线程的标志 */

    bool m_bRun;


    /** 初始化是否成功 */

    bool m_bInit;


    /** 用于向线程发送信令用 */

    int m_socketFD;

    int m_socketForNotify;

    unsigned short m_uPort;


    /** 最多的socket数量 */

    static const int MAX_SOCKET_NUM = 32;


    /** 最大的命令长度 */

    static const int MAX_COM_LEN = 20;


    const unsigned short SOCKET_NOTIFY_PORT;


};


#endif


 

 

/** cpp文件 */


#include <iostream>


#include "socketNotifier.hpp" 


CSocketNotifier::CSocketNotifier()

: m_bRun( true )

, SOCKET_NOTIFY_PORT( 1924 )

{

    /** do-while 为了初始化失败时break */

    do 

    {

        /** 线程中用于接受主线程发出的控制信令的socket */

        if ( ( m_socketFD = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 )

        {

            m_bInit = false;

            perror( "m_socketFD init failed!" );

            break;

        }

        /** 用于向线程发送信令的socket */

        if ( ( m_socketForNotify = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 )

        {

            m_bInit = false;

            perror( "m_socketForNotify init failed!" );

            break;

        }

        sockaddr_in localAddr;

        m_uPort = getFreePort();

        localAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );

        localAddr.sin_family = AF_INET;

        localAddr.sin_port = htons( m_uPort );

        if ( bind( m_socketFD, ( sockaddr* )&localAddr, sizeof( sockaddr ) ) == -1 )

        {

            m_bInit = false;

            perror( "Socket bind failed!" );

            break;

        }

        SOCKPARAM* pParam = new SOCKPARAM;

        pParam->pUsr = ( void* )this;

        pParam->sock_fd = m_socketFD;


        /** 开线程select */

        int ret = pthread_create( &m_threadID, NULL, waitForEvent, pParam );

        if ( 0 != ret )

        {

            perror( "CSocketNotifier:CSocketNotifier" );

            m_bInit = false;

        }

        else

        {

            m_bInit = true;

        }


    } while ( 0 );

}


CSocketNotifier::~CSocketNotifier()

{

    m_bRun = false;

    pthread_join( m_threadID, NULL );

}


bool CSocketNotifier::registerSocket( int sock_fd, sockCallBack pFun, void* pParam )

{

    if ( sock_fd < 0 )

    {

        std::cout<<"Illegal param!"<<std::endl;

        return false;

    }


    /** 如果找到就说明已经有注册过,不用再注册 */

    if ( m_aFun.find( sock_fd ) != m_aFun.end() )

    {

        return true;

    }

    /** 如果没找到则要添加 */

    m_aFun[sock_fd] = std::make_pair<sockCallBack, void*>( pFun, pParam);


    /** 通知select线程添加新的socket */

    if ( !sendNoticeToThread( sock_fd ) )

    {

        return false;

    }


    return true;

}


bool CSocketNotifier::unregisterSocket( int sock_fd )

{

    if ( sock_fd < 0 )

    {

        std::cout<<"Illegal param!"<<std::endl;

        return false;

    }

    /** 找到就删 */

    if ( m_aFun.find( sock_fd ) != m_aFun.end() )

    {

        m_aFun.erase( sock_fd );

    }


    /** 通知select线程删除socket */

    if ( !sendNoticeToThread( sock_fd ) )

    {

        return false;

    }


    return true;

}


bool CSocketNotifier::renewFD( int event_fd, std::set<int> &fdSet, fd_set *pre_fdsr, int &iMaxFD )

{

    /** 是已经有了的socket,说明是要移除 */

    if ( FD_ISSET( event_fd, pre_fdsr ) )

    {

        /** 移除后找到最大的socket */

        iMaxFD = 0;

        std::set<int>::const_iterator it = fdSet.begin();

        for ( ; it != fdSet.end(); ++it )

        {

            if ( *it > iMaxFD )

            {

                iMaxFD = *it;

            }

        }

        FD_CLR( event_fd, pre_fdsr );

        fdSet.erase( event_fd );

        std::cout<<"Remove a fd"<<std::endl;

    }

    /** 是已新来的socket,说明是要添加 */

    else

    {

        if ( event_fd == iMaxFD )

        {

            if ( event_fd > iMaxFD )

            {

                iMaxFD = event_fd;

            }

        }

        FD_SET( event_fd, pre_fdsr );

        fdSet.insert( event_fd );

        std::cout<<"Add a fd"<<std::endl;

    } 


    return true;

}


void* CSocketNotifier::waitForEvent( void* param )

{

    SOCKPARAM* pParam = ( SOCKPARAM* )param;

    CSocketNotifier *pSocketNotifier = ( CSocketNotifier * )( pParam->pUsr );

    std::set<int> fdSet;


    fd_set fdsr, pre_fdsr;

    FD_ZERO( &pre_fdsr );

    FD_ZERO( &pre_fdsr );

    FD_SET( pParam->sock_fd, &pre_fdsr );

    fdSet.insert( pParam->sock_fd );


    struct timeval tv;

    tv.tv_sec = 30;

    tv.tv_usec = 0;


    /** 最大的sock */

    int iMaxFD = pParam->sock_fd;


    int iEvenNum;


    while ( 1 )

    {

        memcpy( &fdsr, &pre_fdsr, sizeof( fd_set ) ); 

        iEvenNum = select( iMaxFD + 1, &fdsr, NULL, NULL, &tv );

        /** 时间到 */

        if ( 0 == iEvenNum )

        {

            continue;

        }

        /** 出错 */

        else if ( 0 > iEvenNum )

        {

            perror( "select" );

            break;

        }

        /** 正常处理 */

        else

        {

            /** 主线程发来的控制信令 */

            if ( FD_ISSET( pParam->sock_fd, &fdsr ) )

            {

                char szRecvBuf[MAX_COM_LEN + 1];

                unsigned int uiRecvLen;

                socklen_t iSockAddrLen = sizeof( struct sockaddr );

                struct sockaddr_in stClientAddr;

                int event_fd;

                int iRet = recvfrom( pParam->sock_fd,

                                     szRecvBuf,

                                     MAX_COM_LEN,

                                     0,

                                     ( struct sockaddr * ) ( &stClientAddr ),

                                     &iSockAddrLen );

                /** 网络错误或关闭时返回 */

                if ( 0 == uiRecvLen || -1 == uiRecvLen )

                {

                    perror( "CSocketNotifier: recvfrom" );

                    break;

                }

                memcpy( &event_fd, szRecvBuf, sizeof( int ) );

                /** 更新socket集合 */

                renewFD( event_fd, fdSet, &pre_fdsr, iMaxFD );

                --iEvenNum;

            }


            /** 通知回调函数 */

            pSocketNotifier->notify( &fdsr, iEvenNum );

        }


    }


    delete pParam;

    return NULL;

}


bool CSocketNotifier::notify( fd_set* pfdsr, int iEventNum )

{

    /** RemainToDo 加锁 */

    std::map< int, std::pair< sockCallBack, void* > >::const_iterator it = m_aFun.begin();


    for ( ; ( it != m_aFun.end() ) && ( iEventNum != 0 ); ++it )

    {

        if ( FD_ISSET( it->first, pfdsr ) )

        {

            ( *( it->second.first ) )( it->second.second );

            --iEventNum;

        }

    }


    return true;

}


unsigned short CSocketNotifier::getFreePort()

{

    /** 暂时未实现 */

    return SOCKET_NOTIFY_PORT;

}


bool CSocketNotifier::sendNoticeToThread( int sock_fd )

{

    int iRet;

    char buf[ MAX_COM_LEN ] = { 0 };

    sockaddr_in localAddr;

    localAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );

    localAddr.sin_port = htons( m_uPort );

    localAddr.sin_family = AF_INET;

    memset( localAddr.sin_zero, 0, sizeof( localAddr.sin_zero ) );

    memcpy( buf, &sock_fd, sizeof( int ) );


    iRet = sendto( m_socketForNotify, 

                   buf, 

                   MAX_COM_LEN, 

                   0, 

                   ( sockaddr* )&localAddr,

                   sizeof( sockaddr ) );

    if ( -1 == iRet)

    {

        perror( "CSocketNotifier:sendNoticeToThread" );

        return false;

    }

    return true;

}

 

 

 

2017-06-28 18:07:03 if9600 阅读数 1015

一、关于I/O       

       一次I/O分两个部分(①等待数据就绪 ②进行I/O),减少等的比重,增加I/O的比重就可以达到高效服务器的目的。select工作原理就是这个,同时监控多个文件描述符(或者说文件句柄),一旦其中某一个进入就绪状态,就进行I/O操作。监控多个文件句柄可以达到提高就绪状态出现的概率,就可以使CPU在大多数时间下都处于忙碌状态,大大提高CPU的性能。达到高效服务器的目的。可以理解为select轮询监控多个文件句柄或套接字。


二、关于select函数


fd_set是文件描述符集,本身是一种位图结构,下面的宏提供了对这个文件描述符集的操作:



三、关于select模型

对于文件描述符集合fd_set,fd_set中的每一个比特位都对于一个文件描述符fd,假设fd_set长度为一字节,则:

1)执行fd_set set,FD_ZERO(&set);则set用位表示为0000,0000;

2)fd = 5时,执行FD_SET(fd, &set);此时set位表示为0001,0000;

3)再加入fd = 2,fd = 1,set位表示为0001,0011;

4)执行select(6,&set,0, 0 , 0)阻塞等待;

5)fd = 1和fd = 2上都发生可读事件,select返回,此时set变为0000,0011(没有事件发生的fd=5被清空)


从上面可以看出select模型的特点:

(1)可监控的文件描述符的个数由sizeof(fd_set)决定,(我用的centos6.5虚拟机上为1024)

(2)将fd加入select监控集的同时,需要用一个array来保存这些文件描述符,一是用于select返回后,array作为源数据和fd_set进行FD_ISSET判断,二是select返回后会把之前加入的但并无事件发生的文件描述符清空,则每次开始select之前都要从array中取得fd再加入,扫描array时取得fd最大值maxfd作为select的第一个参数

(3)每次select之前都要循环array(加fd,取maxfd),select返回之后还要再循环array(进行FD_ISSET判断)


这样也就可以看出select模型的缺陷:

1、每次进行select都要把文件描述符集fd由用户态拷贝到内核态,这样的开销会很大。 
2、实现select服务器,内部要不断对文件描述符集fd进行循环遍历,当fd很多时,开销也很大,实现也较为复杂 
3、select能监控文件描述符的数量有限。


四、实现select服务器

为了实现简单,我这里只考虑了读文件描述符:

select_server.c:

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>

int fds_array_read[sizeof(fd_set)*8];
//int fds_array_write[sizeof(fd_set)*8];

int startup(const char* _ip, int _port)
{
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if(sock < 0)
	{
		perror("socket");
		exit(2);
	}

	//int opt = 1;
	//setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	struct sockaddr_in local;
	local.sin_family = AF_INET;
	local.sin_port = htons(_port);
	local.sin_addr.s_addr = inet_addr(_ip);
	if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
	{
		perror("bind");
		exit(3);
	}

	if(listen(sock, 10) < 0)
	{
		perror("listen");
		exit(4);
	}
	return sock;
}

static void usage(const char* proc)
{
	printf("Usage: [local_ip] [local_port] %s\n", proc);
}

int main(int argc, char* argv[])
{
	if(argc != 3)
	{
		usage(argv[0]);
		return 1;
	}
	int listen_sock = startup(argv[1], atoi(argv[2]));
	
	int i = 0;
	int nums = sizeof(fds_array_read)/sizeof(fds_array_read[0]);
	for(; i<nums; ++i)
	{
		fds_array_read[i] = -1;
	}
	fds_array_read[0] = listen_sock;
	int maxfd = listen_sock;
	while(1)
    {
		fd_set rfds;
		FD_ZERO(&rfds);
		for(i=0; i<nums; ++i)
		{
			if(fds_array_read[i] == -1)
				continue;
			FD_SET(fds_array_read[i], &rfds);
			if(maxfd < fds_array_read[i])
			{
				maxfd = fds_array_read[i];
			}
			struct timeval timeout = {3, 0};
			switch(select(maxfd+1, &rfds, NULL, NULL, &timeout))
			{
				case 0:
				printf("timeout...\n");
					break;
				case -1:
					perror("select");
					break;
				default:
					{
						for(i=0; i<nums; ++i)
						{
							if(fds_array_read[i] < 0)
								continue;
							if(i==0 && FD_ISSET(listen_sock, &rfds))
							{
								struct sockaddr_in client;
								socklen_t len = sizeof(client);
								int new_sock = accept(listen_sock, \
								   (struct sockaddr*)&client, &len);
								if(new_sock < 0)
								{
									perror("accept");
									continue;
								}
								int j = 1;
								for(; j<nums; ++j)
								{
									if(fds_array_read[j] < 0)
										break;
								}
								if(j == nums)
									close(new_sock);
								else
									fds_array_read[j] = new_sock;
							}
							else if(i!= 0 && FD_ISSET(fds_array_read[i], &rfds))
							{
								char buf[1024];
								ssize_t s = read(fds_array_read[i], buf, sizeof(buf)-1);
								if(s > 0)
								{
									buf[s] = 0;
									printf("client# %s\n", buf);
								}
								else if(s == 0)
								{
									printf("client is quit...\n");
									close(fds_array_read[i]);
									fds_array_read[i] = -1;
                                                                }
								else
								{
									printf("client is quit...\n");
									close(fds_array_read[i]);
									fds_array_read[i] = -1;
								}
							}
						}
					}
			}
		}
	}
}

运行结果:

(使用telnet命令远程登录本地环回实现通信)



2016-05-11 23:59:08 naruto2011sasuke 阅读数 346

select原理

Linux 系统编程——与内核和 C 库直接对话
select能轮询一个管道端口(文件,网络),若有数据

select例子

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

const int TIMEOUT = 5;
const int BUF_LEN = 1024;

int main() {
    struct timeval tv;
    fd_set readfds;
    int ret;

    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);

    tv.tv_sec = TIMEOUT;
    tv.tv_usec = 0;

    ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
    if (ret == -1) {
        perror("select");
        return 1;
    } else if (!ret) {
        printf("%d seconds elapsed.\n", TIMEOUT);
        return 0;
    }

    if (FD_ISSET(STDIN_FILENO, &readfds)) {
        char buf[BUF_LEN + 1];
        int len;
        len = read(STDIN_FILENO, buf, BUF_LEN);
        if (len == -1) {
            perror("read");
            return 1;
        }
        if (len) {
            buf[len] = '\0';
            printf("read:%s\n", buf);
        }
        return 0;
    }
    fprintf(stderr, "This should not happend!\n");
    return 1;
}
2014-07-24 10:39:45 yuanfengyun 阅读数 523
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MYPORT 1234    // the port users will be connecting to

#define BACKLOG 5     // how many pending connections queue will hold

#define BUF_SIZE 1024

int fd_A[BACKLOG];    // accepted connection fd
int conn_amount;    // current connection amount

void showclient()
{
    int i;
    printf("client amount: %d\n", conn_amount);
    printf("\n\n");
}

int main(void)
{
    int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct sockaddr_in server_addr;    // server address information
    struct sockaddr_in client_addr; // connector's address information
    socklen_t sin_size;
    int yes = 1;
    char buf[BUF_SIZE];
    int ret;
    int i;

    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }
    
    server_addr.sin_family = AF_INET;         // host byte order
    server_addr.sin_port = htons(MYPORT);     // short, network byte order
    server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

    if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sock_fd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    printf("listen port %d\n", MYPORT);

    fd_set fdsr;
    int maxsock;
    struct timeval tv;

    conn_amount = 0;
    sin_size = sizeof(client_addr);
    maxsock = sock_fd;
    while (1) {
        // initialize file descriptor set
        FD_ZERO(&fdsr);
        FD_SET(sock_fd, &fdsr);

        // timeout setting
        tv.tv_sec = 30;
        tv.tv_usec = 0;

        // add active connection to fd set
        for (i = 0; i < BACKLOG; i++) {
            if (fd_A[i] != 0) {
                FD_SET(fd_A[i], &fdsr);
            }
        }

        ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
        if (ret < 0) {
            perror("select");
            break;
        } else if (ret == 0) {
            printf("timeout\n");
            continue;
        }

        // check every fd in the set
        for (i = 0; i < conn_amount; i++) {
            if (FD_ISSET(fd_A[i], &fdsr)) {
                ret = recv(fd_A[i], buf, sizeof(buf), 0);
                if (ret <= 0) {        // client close
                    printf("client[%d] close\n", i);
                    close(fd_A[i]);
                    FD_CLR(fd_A[i], &fdsr);
                    fd_A[i] = 0;
                } else {        // receive data
                    if (ret < BUF_SIZE)
                        memset(&buf[ret], '\0', 1);                    
                    printf("client[%d] send:%s\n", i, buf);
            
            
                }
            }
        }

        // check whether a new connection comes
        if (FD_ISSET(sock_fd, &fdsr)) {
            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
            if (new_fd <= 0) {
                perror("accept");
                continue;
            }

            // add to fd queue
            if (conn_amount < BACKLOG) {
                fd_A[conn_amount++] = new_fd;
                printf("new connection client[%d] %s:%d\n", conn_amount,
                        inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                if (new_fd > maxsock)
                    maxsock = new_fd;
            }
            else {
                printf("max connections arrive, exit\n");
                send(new_fd, "bye", 4, 0);
                close(new_fd);
            }
        }
        showclient();
    }

    // close other connections
    for (i = 0; i < BACKLOG; i++) {
        if (fd_A[i] != 0) {
            close(fd_A[i]);
        }
    }

    exit(0);
}
这个代码我也是找了很久的,很不错的,实现的单线程多客户端的。。。
2015-11-24 23:16:16 INGNIGHT 阅读数 359
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <pthread.h>


#define DEF_STD_ERROR (-1)
#define DEF_BIND_PORT (12455)


#ifndef TRUE
#define TRUE 1
#define FALSE 0
#define BOOL int
#endif


//set socket(TRUE:block, FALSE:no block)

void set_block(int sock,BOOL flag)
{
        int ret;
        if(flag == TRUE)
        {
                ret = fcntl(sock,F_GETFL);
                ret ^= O_NONBLOCK;
                fcntl(sock,F_SETFL,ret);
        }
        else
        {
                ret = fcntl(sock,F_GETFL);
                ret |= O_NONBLOCK;
                fcntl(sock,F_SETFL,ret);
        }
}


//thread param 
struct thread_param
{
        fd_set my_set;
        int my_count;
        int my_max;
        pthread_mutex_t my_mutex;
};

void * deal_thread(void *param)
{
        struct thread_param *p=(struct thread_param*)param;
        fd_set read_set;
        int ret;
        int i;
        struct timeval my_tv;
        my_tv.tv_sec = 0;
        my_tv.tv_usec = 10;
        while(1)
        {
                //clear
                FD_ZERO(&read_set);
                //fill
                memcpy(&read_set,&p->my_set,sizeof(read_set));
                //select
                ret = select(p->my_max+1,&read_set,NULL,NULL,&my_tv);
                //judge
                if(ret < 0)
                {
                        printf("%s",strerror(errno));
                        break;
                }
                else if(ret == 0)//chao shi
                {
                        usleep(10);
                        continue;
                }
                //check
                for(i = p->my_max;i>2;i--)
                {
                        if(FD_ISSET(i,&read_set)>0)
                        {
                                //recv
                                printf("sock[%d]:\n",i);
                                sleep(1);
                        }
                }

        }
}


int main(int argc,char *argv[])
{
        int ret;
        int sock;
        struct sockaddr_in addr;
        pid_t child;
        char buf[1024];
        int len;
        pthread_t thread;
        fd_set read_set;
        struct thread_param param;
        param.my_count = 0;
        param.my_max = 2;
        FD_ZERO(¶m.my_set);
        pthread_mutex_init(¶m.my_mutex,NULL);
        //create socket
        sock = socket(AF_INET,SOCK_STREAM,0); 
        if(sock == DEF_STD_ERROR)
        {
                printf("%s",strerror(errno));
                return -1;
        }
        //init address
        addr.sin_family = AF_INET;
        addr.sin_port = htons(DEF_BIND_PORT);
        addr.sin_addr.s_addr = inet_addr("192.168.1.127");
        ret = bind(sock,(struct sockaddr*)&addr,sizeof(addr));
        if(ret == DEF_STD_ERROR)
        {
                printf("%s",strerror(errno));
                close(sock);
                return -1;
        }
        //listen
        ret = listen(sock,5);
        if(ret == DEF_STD_ERROR)
        {
                printf("%s",strerror(errno));
                close(sock);
                return -1;
        }
        //set no block
        set_block(sock,FALSE);
        //accept
        while(1)
        {
                ret = accept(sock,NULL,NULL);
                if(ret == DEF_STD_ERROR)
                {
                        if(errno == EAGAIN)
                        {
                                //printf("yi bu...\n");
                                usleep(10);
                                continue;
                        }
                        else
                        {
                                printf("%s",strerror(errno));
                                break;
                        }
                }
                param.my_max = param.my_max > ret ? param.my_max:ret;
                                //add to read_set
                pthread_mutex_lock(¶m.my_mutex);
                if(param.my_count < 1024)
                {
                        FD_SET(ret,¶m.my_set);
                        param.my_count++;
                }
                //if is first ,create thread
                if(param.my_count == 1)
                {
                        pthread_create(&thread,NULL,deal_thread,¶m);
                }
		pthread_mutex_unlock(¶m.my_mutex);
        }
        //wait child thread
        pthread_join(thread,NULL);//WaitForSignalObject
        //pthread_mutex_destory(¶m.my_mutex);
        //close
        close(sock);
        return 0;
}

没有更多推荐了,返回首页