Socket Server 简单实现.docx

上传人:b****5 文档编号:29845851 上传时间:2023-07-27 格式:DOCX 页数:12 大小:86.76KB
下载 相关 举报
Socket Server 简单实现.docx_第1页
第1页 / 共12页
Socket Server 简单实现.docx_第2页
第2页 / 共12页
Socket Server 简单实现.docx_第3页
第3页 / 共12页
Socket Server 简单实现.docx_第4页
第4页 / 共12页
Socket Server 简单实现.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Socket Server 简单实现.docx

《Socket Server 简单实现.docx》由会员分享,可在线阅读,更多相关《Socket Server 简单实现.docx(12页珍藏版)》请在冰豆网上搜索。

Socket Server 简单实现.docx

SocketServer简单实现

一、基本原理

有时候我们需要实现一个公共的模块,需要对多个其他的模块提供服务,最常用的方式就是实现一个SocketServer,接受客户的请求,并返回给客户结果。

这经常涉及到如果管理多个连接及如何多线程的提供服务的问题,常用的方式就是连接池和线程池,基本流程如下:

首先服务器端有一个监听线程,不断监听来自客户端的连接。

当一个客户端连接到监听线程后,便建立了一个新的连接。

监听线程将新建立的连接放入连接池进行管理,然后继续监听新来的连接。

线程池中有多个服务线程,每个线程都监听一个任务队列,一个建立的连接对应一个服务任务,当服务线程发现有新的任务的时候,便用此连接向客户端提供服务。

一个SocketServer所能够提供的连接数可配置,如果超过配置的个数则拒绝新的连接。

当服务线程完成服务的时候,客户端关闭连接,服务线程关闭连接,空闲并等待处理新的任务。

连接池的监控线程清除其中关闭的连接对象,从而可以建立新的连接。

二、对Socket的封装

Socket的调用主要包含以下的步骤:

调用比较复杂,我们首先区分两类Socket,一类是ListeningSocket,一类是ConnectedSocket.

ListeningSocket由MySocketServer负责,一旦accept,则生成一个ConnectedSocket,又MySocket负责。

MySocket主要实现的方法如下:

intMySocket:

:

write(constchar*buf,intlength)

{

       intret=0;

       intleft=length;

       intindex=0;

       while(left>0)

       {

               ret=send(m_socket,buf+index,left,0);

               if(ret==0)

                       break;

               elseif(ret==-1)

               {

                       break;

               }

               left-=ret;

               index+=ret;

       }

       if(left>0)

               return-1;

       return0;

}

intMySocket:

:

read(char*buf,intlength)

{

       intret=0;

       intleft=length;

       intindex=0;

       while(left>0)

       {

               ret=recv(m_socket,buf+index,left,0);

               if(ret==0)

                       break;

               elseif(ret==-1)

                       return-1;

               left-=ret;

               index+=ret;

       }

       returnindex;

}

intMySocket:

:

status()

{

       intstatus;

       intret;

       fd_setcheckset;

       structtimevaltimeout;

       FD_ZERO(&checkset);

       FD_SET(m_socket,&checkset);

       timeout.tv_sec=10;

       timeout.tv_usec=0;

       status=select((int)m_socket+1,&checkset,0,0,&timeout);

       if(status<0)

               ret=-1;

       elseif(status==0)

               ret=0;

       else

               ret=0;

       returnret;

}

intMySocket:

:

close()

{

       structlingerlin;

       lin.l_onoff=1;

       lin.l_linger=0;

       setsockopt(m_socket,SOL_SOCKET,SO_LINGER,(constchar*)&lin,sizeof(lin));

       :

:

close(m_socket);

       return0;

}

MySocketServer的主要方法实现如下:

intMySocketServer:

:

init(intport)

{

       if((m_socket=socket(AF_INET,SOCK_STREAM,0))==-1)

       {

               return-1;

       }

       structsockaddr_inserverAddr;

       memset(&serverAddr,0,sizeof(structsockaddr_in));

       serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);

       serverAddr.sin_family=AF_INET;

       serverAddr.sin_port=htons(port);

       if(bind(m_socket,(structsockaddr*)&serverAddr,sizeof(serverAddr))==-1)

       {

               :

:

close(m_socket);

               return-1;

       }

       if(listen(m_socket,SOMAXCONN)==-1)

       {

               :

:

close(m_socket);

               return-1;

       }

       structlingerlin;

       lin.l_onoff=1;

       lin.l_linger=0;

       setsockopt(m_socket,SOL_SOCKET,SO_LINGER,(constchar*)&lin,sizeof(lin));

       m_port=port;

       m_inited=true;

       return0;

}

MySocket*MySocketServer:

:

accept()

{

       intsock;

       structsockaddr_inclientAddr;

       socklen_tclientAddrSize=sizeof(clientAddr);

       if((sock=:

:

accept(m_socket,(structsockaddr*)&clientAddr,&clientAddrSize))==-1)

       {

               returnNULL;

       }

       MySocket*socket=newMySocket(sock);

       returnsocket;

}

MySocket*MySocketServer:

:

accept(inttimeout)

{

       structtimevaltimeout;

       timeout.tv_sec=timeout;

       timeout.tv_usec=0;

       fd_setcheckset;

       FD_ZERO(&checkset);

       FD_SET(m_socket,&checkset);

       intstatus=(int)select((int)(m_socket+1),&checkset,NULL,NULL,&timeout);

       if(status<0)

               returnNULL;

       elseif(status==0)

               returnNULL;

       if(FD_ISSET(m_socket,&checkset))

       {

               returnaccept();

       }

}

三、线程池的实现

一个线程池一般有一个任务队列,启动的各个线程从任务队列中竞争任务,得到的线程则进行处理:

list m_taskQueue;

任务队列由锁保护,使得线程安全:

pthread_mutex_tm_queueMutex

任务队列需要条件变量来支持生产者消费者模式:

pthread_cond_tm_cond

如果任务列表为空,则线程等待,等待中的线程个数为:

m_numWaitThreads

需要一个列表来维护线程池中的线程:

vectorm_threads

每个线程需要一个线程运行函数:

void*__thread_new_proc(void*p)

{

   ((MyThread*)p)->run();

   return0;

}

每个线程由MyThread类负责,主要函数如下:

intMyThread:

:

start()

{

   pthread_attr_t attr;

   pthread_attr_init(&attr);

   pthread_attr_setschedpolicy(&attr,SCHED_FIFO);

   intret=pthread_create(&m_thread,&attr,thread_func,args);

   pthread_attr_destroy(&attr);

   if(ret!

=0)

       return–1;

}

intMyThread:

:

stop()

{

   intret=pthread_kill(m_thread,SIGINT);

   if(ret!

=0)

       return–1;

}

intMyThread:

:

join()

{

   intret=pthread_join(m_thread,NULL);

   if(ret!

=0)

       return–1;

}

voidMyThread:

:

run()

{

   while(false==m_bStop)

   {

       MyTask*pTask=m_threadPool->getNextTask();

       if(NULL!

=pTask)

       {

           pTask->process();

       }

   }

}

线程池由MyThreadPool负责,主要函数如下:

intMyThreadPool:

:

init()

{

   pthread_condattr_tcond_attr;

   pthread_condattr_init(&cond_attr);

   pthread_condattr_setpshared(&cond_attr,PTHREAD_PROCESS_SHARED);

   intret= pthread_cond_init(&m_cond,&cond_attr);

   pthread_condattr_destroy(&cond_attr);

   if(ret_val!

=0)

       return–1;

   pthread_mutexattr_tattr;

   pthread_mutexattr_init(&attr);

   pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);

   ret=pthread_mutex_init(&m_queueMutex,&attr);

   pthread_mutexattr_destroy(&attr);

   if(ret_val!

=0)

       return–1;

   for(inti=0;i

   {

       MyThread*thread=newMyThread(i+1,this);       

       m_threads.push_back(thread);

   }

   return0;

}

intMyThreadPool:

:

start()

{

   intret;

   for(inti=0;i

   {       

      ret=m_threads[i]->start();

      if(ret!

=0)

          break;      

   }

   ret=pthread_cond_broadcast(&m_cond);

   if(ret!

=0)

       return–1;

   return0;

}

voidMyThreadPool:

:

addTask(MyTask*ptask)

{

   if(NULL==ptask)

       return;

   pthread_mutex_lock(&m_queueMutex);

   m_taskQueue.push_back(ptask);       

   if(m_waitingThreadCount>0)

       pthread_cond_signal(&m_cond);

   pthread_mutex_unlock(&m_queueMutex);

}

MyTask*MyThreadPool:

:

getNextTask()

{

   MyTask*pTask=NULL; 

   pthread_mutex_lock(&m_queueMutex);

   while(m_taskQueue.begin()==m_taskQueue.end())

   { 

       ++m_waitingThreadCount;

       pthread_cond_wait(&n_cond,&m_queueMutex);

       --m_waitingThreadCount;      

   }   

   pTask=m_taskQueue.front();

   m_taskQueue.pop_front();

   pthread_mutex_unlock(&m_queueMutex);

   returnpTask;  

}

其中每一个任务的执行由MyTask负责,其主要方法如下:

voidMyTask:

:

process()

{

   //用read从客户端读取指令

   //对指令进行处理

   //用write向客户端写入结果

}

 

四、连接池的实现

每个连接池保存一个链表保存已经建立的连接:

list*m_connections

当然这个链表也需要锁来进行多线程保护:

pthread_mutex_tm_connectionMutex;

此处一个MyConnection也是一个MyTask,由一个线程来负责。

线程池也作为连接池的成员变量:

MyThreadPool*m_threadPool   

连接池由类MyConnectionPool负责,其主要函数如下:

voidMyConnectionPool:

:

addConnection(MyConnection*pConn)

{

   pthread_mutex_lock(&m_connectionMutex);

   m_connections->push_back(pConn);

   pthread_mutex_unlock(&m_connectionMutex);

   m_threadPool->addTask(pConn);

}

MyConnectionPool也要启动一个背后的线程,来管理这些连接,移除结束的连接和错误的连接。

voidMyConnectionPool:

:

managePool()

{

   pthread_mutex_lock(&m_connectionMutex);

   for(list:

:

iteratoritr=m_connections->begin();itr!

=m_connections->end();)

   {

       MyConnection*conn=*itr;       

       if(conn->isFinish())

       {

           deleteconn;

           conn=NULL;

           list:

:

iteratorpos=itr++;

           m_connections->erase(pos);                        

       }

       elseif(conn->isError())

       {

           //处理错误的连接

           ++itr;

       }

       else

       {

           ++itr;

       }

   }

   pthread_mutex_unlock(&m_connectionMutex);

}

 

五、监听线程的实现

监听线程需要有一个MySocketServer来监听客户端的连接,每当形成一个新的连接,查看是否超过设置的最大连接数,如果超过则关闭连接,如果未超过设置的最大连接数,则形成一个新的MyConnection,将其加入连接池和线程池。

MySocketServer*pServer=newMySocketServer(port);

MyConnectionPool*pPool=newMyConnectionPool();

while(!

stopFlag)

{

   MySocket*sock=pServer->acceptConnection(5);

   if(sock!

=null)

   {

       if(m_connections.size>maxConnectionSize)

       {

           sock.close();

       }

       MyTask*pTask=newMyConnection();

       pPool->addConnection(pTask);      

   }

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 计算机软件及应用

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1