Socket Server 简单实现.docx
- 文档编号:29845851
- 上传时间:2023-07-27
- 格式:DOCX
- 页数:12
- 大小:86.76KB
Socket Server 简单实现.docx
《Socket Server 简单实现.docx》由会员分享,可在线阅读,更多相关《Socket Server 简单实现.docx(12页珍藏版)》请在冰豆网上搜索。
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
任务队列由锁保护,使得线程安全:
pthread_mutex_tm_queueMutex
任务队列需要条件变量来支持生产者消费者模式:
pthread_cond_tm_cond
如果任务列表为空,则线程等待,等待中的线程个数为:
m_numWaitThreads
需要一个列表来维护线程池中的线程:
vector
每个线程需要一个线程运行函数:
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 当然这个链表也需要锁来进行多线程保护: 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); } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Socket Server 简单实现 简单 实现