- 浏览: 369815 次
- 性别:
- 来自: 苏州
文章分类
- 全部博客 (335)
- C++ (190)
- 设计模式 (43)
- 数据库技术 (5)
- 网络编程 (11)
- 自动化测试 (6)
- Linux (13)
- OpenSSL (10)
- MS Crypt API (5)
- SCM (2)
- English (4)
- Android (10)
- EMV规范 (1)
- Saturn Platform (0)
- C (10)
- SQL (2)
- ASP.NET (3)
- 英语口语学习 (3)
- 调试工具 (21)
- 编译技术 (5)
- UML (1)
- 项目管理 (5)
- 敏捷开发 (2)
- Http Server (6)
- 代码审查、代码分析 (5)
- 面试基础 (10)
- 重点知识 (16)
- STL (6)
- Efficient C++资料 (8)
- 数据结构和算法 (7)
- 读书笔记 (0)
- 开源项目 (4)
- 多线程 (2)
- Console App (6)
- 个人开源项目 (4)
- IBM DevelopWorks (4)
- Java (16)
- 内存泄漏相关调试和检测 (13)
- 软件测试相关技术 (2)
- C# (11)
- Apple Related (1)
- 软件测试和管理 (2)
- EMV (1)
- Python (1)
- Node.js (6)
- JavaScript (5)
- VUE (1)
- Frontend (1)
- Backend (4)
- RESTful API (3)
- Firebase (3)
最新评论
-
u013189503:
来个密码吧
[C++][Logging] 项目中写日志模块的实现 -
wyf_vc:
来个密码啊!!
[C++][Logging] 项目中写日志模块的实现
转自
http://www.cnblogs.com/forfuture1978/archive/2010/09/12/1824443.html
一、基本原理
有时候我们需要实现一个公共的模块,需要对多个其他的模块提供服务,最常用的方式就是实现一个Socket Server,接受客户的请求,并返回给客户结果。
这经常涉及到如果管理多个连接及如何多线程的提供服务的问题,常用的方式就是连接池和线程池,基本流程如下:
1。首先服务器端有一个监听线程,不断监听来自客户端的连接。
2.当一个客户端连接到监听线程后,便建立了一个新的连接。
3.监听线程将新建立的连接放入连接池进行管理,然后继续监听新来的连接。
4.线程池中有多个服务线程,每个线程都监听一个任务队列,一个建立的连接对应一个服务任务,当服务线程发现有新的任务的时候,便用此连接向客户端提供服务。
5.一个Socket Server所能够提供的连接数可配置,如果超过配置的个数则拒绝新的连接。
6.当服务线程完成服务的时候,客户端关闭连接,服务线程关闭连接,空闲并等待处理新的任务。
7.连接池的监控线程清除其中关闭的连接对象,从而可以建立新的连接。
二、对Socket的封装
Socket的调用主要包含以下的步骤:
clip_image001
调用比较复杂,我们首先区分两类Socket,一类是Listening Socket,一类是Connected Socket.
Listening Socket由MySocketServer负责,一旦accept,则生成一个Connected Socket,又MySocket负责。
MySocket主要实现的方法如下:
MySocketServer的主要方法实现如下:
三、线程池的实现
一个线程池一般有一个任务队列,启动的各个线程从任务队列中竞争任务,得到的线程则进行处理:list<MyTask *> m_taskQueue;
任务队列由锁保护,使得线程安全:pthread_mutex_t m_queueMutex
任务队列需要条件变量来支持生产者消费者模式:pthread_cond_t m_cond
如果任务列表为空,则线程等待,等待中的线程个数为:m_numWaitThreads
需要一个列表来维护线程池中的线程:vector<MyThread *> m_threads
每个线程需要一个线程运行函数:
每个线程由MyThread类负责,主要函数如下:
线程池由MyThreadPool负责,主要函数如下:
其中每一个任务的执行由MyTask负责,其主要方法如下:
四、连接池的实现
每个连接池保存一个链表保存已经建立的连接:list<MyConnection *> * m_connections
当然这个链表也需要锁来进行多线程保护:pthread_mutex_t m_connectionMutex;
此处一个MyConnection也是一个MyTask,由一个线程来负责。
线程池也作为连接池的成员变量:MyThreadPool * m_threadPool
连接池由类MyConnectionPool负责,其主要函数如下:
MyConnectionPool也要启动一个背后的线程,来管理这些连接,移除结束的连接和错误的连接。
五、监听线程的实现
监听线程需要有一个MySocketServer来监听客户端的连接,每当形成一个新的连接,查看是否超过设置的最大连接数,如果超过则关闭连接,如果未超过设置的最大连接数,则形成一个新的MyConnection,将其加入连接池和线程池。
http://www.cnblogs.com/forfuture1978/archive/2010/09/12/1824443.html
一、基本原理
有时候我们需要实现一个公共的模块,需要对多个其他的模块提供服务,最常用的方式就是实现一个Socket Server,接受客户的请求,并返回给客户结果。
这经常涉及到如果管理多个连接及如何多线程的提供服务的问题,常用的方式就是连接池和线程池,基本流程如下:
1。首先服务器端有一个监听线程,不断监听来自客户端的连接。
2.当一个客户端连接到监听线程后,便建立了一个新的连接。
3.监听线程将新建立的连接放入连接池进行管理,然后继续监听新来的连接。
4.线程池中有多个服务线程,每个线程都监听一个任务队列,一个建立的连接对应一个服务任务,当服务线程发现有新的任务的时候,便用此连接向客户端提供服务。
5.一个Socket Server所能够提供的连接数可配置,如果超过配置的个数则拒绝新的连接。
6.当服务线程完成服务的时候,客户端关闭连接,服务线程关闭连接,空闲并等待处理新的任务。
7.连接池的监控线程清除其中关闭的连接对象,从而可以建立新的连接。
二、对Socket的封装
Socket的调用主要包含以下的步骤:
clip_image001
调用比较复杂,我们首先区分两类Socket,一类是Listening Socket,一类是Connected Socket.
Listening Socket由MySocketServer负责,一旦accept,则生成一个Connected Socket,又MySocket负责。
MySocket主要实现的方法如下:
int MySocket::write(const char * buf, int length) { int ret = 0; int left = length; int index = 0; while(left > 0) { ret = send(m_socket, buf + index, left, 0); if(ret == 0) break; else if(ret == -1) { break; } left -= ret; index += ret; } if(left > 0) return -1; return 0; } int MySocket::read(char * buf, int length) { int ret = 0; int left = length; int index = 0; while(left > 0) { ret = recv(m_socket, buf + index, left, 0); if(ret == 0) break; else if(ret == -1) return -1; left -= ret; index += ret; } return index; } int MySocket::status() { int status; int ret; fd_set checkset; struct timeval timeout; 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; else if(status == 0) ret = 0; else ret = 0; return ret; } int MySocket::close() { struct linger lin; lin.l_onoff = 1; lin.l_linger = 0; setsockopt(m_socket, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(lin)); ::close(m_socket); return 0; }
MySocketServer的主要方法实现如下:
int MySocketServer::init(int port) { if((m_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(struct sockaddr_in)); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); if(bind(m_socket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) { ::close(m_socket); return -1; } if(listen(m_socket, SOMAXCONN) == -1) { ::close(m_socket); return -1; } struct linger lin; lin.l_onoff = 1; lin.l_linger = 0; setsockopt(m_socket, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(lin)); m_port = port; m_inited = true; return 0; } MySocket * MySocketServer::accept() { int sock; struct sockaddr_in clientAddr; socklen_t clientAddrSize = sizeof(clientAddr); if((sock = ::accept(m_socket, (struct sockaddr *)&clientAddr, &clientAddrSize)) == -1) { return NULL; } MySocket* socket = new MySocket(sock); return socket; } MySocket * MySocketServer::accept(int timeout) { struct timeval timeout; timeout.tv_sec = timeout; timeout.tv_usec = 0; fd_set checkset; FD_ZERO(&checkset); FD_SET(m_socket, &checkset); int status = (int)select((int)(m_socket + 1), &checkset, NULL, NULL, &timeout); if(status < 0) return NULL; else if(status == 0) return NULL; if(FD_ISSET(m_socket, &checkset)) { return accept(); } }
三、线程池的实现
一个线程池一般有一个任务队列,启动的各个线程从任务队列中竞争任务,得到的线程则进行处理:list<MyTask *> m_taskQueue;
任务队列由锁保护,使得线程安全:pthread_mutex_t m_queueMutex
任务队列需要条件变量来支持生产者消费者模式:pthread_cond_t m_cond
如果任务列表为空,则线程等待,等待中的线程个数为:m_numWaitThreads
需要一个列表来维护线程池中的线程:vector<MyThread *> m_threads
每个线程需要一个线程运行函数:
void * __thread_new_proc(void *p) { ((MyThread *)p)->run(); return 0; }
每个线程由MyThread类负责,主要函数如下:
int MyThread::start() { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); int ret = pthread_create(&m_thread, &attr, thread_func, args); pthread_attr_destroy(&attr); if(ret != 0) return –1; } int MyThread::stop() { int ret = pthread_kill(m_thread, SIGINT); if(ret != 0) return –1; } int MyThread::join() { int ret = pthread_join(m_thread, NULL); if(ret != 0) return –1; } void MyThread::run() { while (false == m_bStop) { MyTask *pTask = m_threadPool->getNextTask(); if (NULL != pTask) { pTask->process(); } } }
线程池由MyThreadPool负责,主要函数如下:
int MyThreadPool::init() { pthread_condattr_t cond_attr; pthread_condattr_init(&cond_attr); pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); int ret = pthread_cond_init(&m_cond, &cond_attr); pthread_condattr_destroy(&cond_attr); if (ret_val != 0) return –1; pthread_mutexattr_t attr; 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 (int i = 0; i< m_poolSize; ++i) { MyThread *thread = new MyThread(i+1, this); m_threads.push_back(thread); } return 0; } int MyThreadPool::start() { int ret; for (int i = 0; i< m_poolSize; ++i) { ret = m_threads[i]->start(); if (ret != 0) break; } ret = pthread_cond_broadcast(&m_cond); if(ret != 0) return –1; return 0; } void MyThreadPool::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); return pTask; }
其中每一个任务的执行由MyTask负责,其主要方法如下:
void MyTask::process() { //用read从客户端读取指令 //对指令进行处理 //用write向客户端写入结果 }
四、连接池的实现
每个连接池保存一个链表保存已经建立的连接:list<MyConnection *> * m_connections
当然这个链表也需要锁来进行多线程保护:pthread_mutex_t m_connectionMutex;
此处一个MyConnection也是一个MyTask,由一个线程来负责。
线程池也作为连接池的成员变量:MyThreadPool * m_threadPool
连接池由类MyConnectionPool负责,其主要函数如下:
void MyConnectionPool::addConnection(MyConnection * pConn) { pthread_mutex_lock(&m_connectionMutex); m_connections->push_back(pConn); pthread_mutex_unlock(&m_connectionMutex); m_threadPool->addTask(pConn); }
MyConnectionPool也要启动一个背后的线程,来管理这些连接,移除结束的连接和错误的连接。
void MyConnectionPool::managePool() { pthread_mutex_lock(&m_connectionMutex); for (list<MyConnection *>::iterator itr = m_connections->begin(); itr!=m_connections->end(); ) { MyConnection *conn = *itr; if (conn->isFinish()) { delete conn; conn = NULL; list<MyConnection *>::iterator pos = itr++; m_connections->erase(pos); } else if (conn->isError()) { //处理错误的连接 ++itr; } else { ++itr; } } pthread_mutex_unlock(&m_connectionMutex); }
五、监听线程的实现
监听线程需要有一个MySocketServer来监听客户端的连接,每当形成一个新的连接,查看是否超过设置的最大连接数,如果超过则关闭连接,如果未超过设置的最大连接数,则形成一个新的MyConnection,将其加入连接池和线程池。
MySocketServer *pServer = new MySocketServer(port); MyConnectionPool *pPool = new MyConnectionPool(); while (!stopFlag) { MySocket * sock = pServer->acceptConnection(5); if(sock != null) { if(m_connections.size > maxConnectionSize) { sock.close(); } MyTask *pTask = new MyConnection(); pPool->addConnection(pTask); } }
发表评论
-
FreeRTOS
2022-03-05 16:31 248Ref https://blog.csdn.net/weix ... -
Python: HTTP文件下载压力测试工具
2020-12-15 17:45 490import urllib.request import ... -
串口通讯相关
2018-11-02 13:44 411https://bbs.csdn.net/wap/topics ... -
[转]C++验证IP是否可以PING通
2018-10-30 17:54 1325https://www.cnblogs.com/guoyz13 ... -
C++/MFC 換皮膚
2018-10-20 11:05 477https://blog.csdn.net/u01123991 ... -
WinCE 截屏 - C++ 代碼
2018-08-31 09:45 574// this function create a bmp ... -
Android NDK搭建環境
2017-11-27 13:25 580https://www.cnblogs.com/ut2016- ... -
8583协议相关
2017-10-17 13:38 5738583相关资料,整理中... -
Java高级应用之JNI
2017-06-19 09:00 600参考link http://www.cnblogs.com/l ... -
C++实现ping功能
2017-04-18 11:21 2155基础知识 ping的过程是向目的IP发送一个type=8的I ... -
OpenSSL 编译环境搭建
2017-03-27 15:01 9061 安裝VS2008到 c:\Program Files (x ... -
最优非对称加密填充(OAEP)
2017-03-25 14:53 1582OpenSSL命令---rsautl http://blog. ... -
[Platform Builder] 设置SVM OS build Env
2016-11-10 11:39 01 copy one OSDesign Project to ... -
[Windows] System Error Codes(GetLastError )0-----5999
2016-10-26 13:28 1881ERROR_SUCCESS 0 (0x0) T ... -
开源Windows驱动程序框架
2016-09-17 21:35 871转自 http://code.csdn.net/news/28 ... -
c/c++代码中执行cmd命令
2016-09-14 14:50 1908转自 http://blog.csdn.net/slixinx ... -
C#使用C++标准DLL实例(包含callback)
2016-09-11 19:44 1086C++编写标准Win32DLL如下 头文件 /***** ... -
C#调用C++的DLL搜集整理的所有数据类型转换方式
2016-09-09 16:07 969转自 http://www.cnblogs.com/zeroo ... -
WinCE CPU使用率计算 测试工具
2016-09-08 16:14 991转自 http://blog.csdn.net/jan ... -
switch在C++与C#中的一些差异
2016-09-08 15:19 810参考链接 http://blog.csdn.net/weiwe ...
相关推荐
在Linux中,Socket可以基于TCP或UDP协议,其中TCP提供面向连接的服务,UDP则提供无连接的服务。 2. **Socket API**:在Linux下,Socket API包括一系列函数,如`socket()`、`bind()`、`listen()`、`accept()`、`...
在Unix系统中,socket分为流式(SOCK_STREAM,TCP)和数据报式(SOCK_DGRAM,UDP)两种类型,本示例中可能使用的是流式socket,因为TCP提供面向连接、可靠的数据传输。 服务器端(server.cpp)通常包括以下步骤: 1...
本篇文章将详细探讨如何使用C++通过socket编程来实现面向连接的TCP通信。 首先,TCP是一种面向连接的协议,意味着在数据交换之前,必须先建立两端之间的连接。这一过程通常包括三次握手,确保双方都有能力并准备好...
TCP提供的是面向连接、可靠的、基于字节流的通信服务,而UDP则是无连接、不可靠的、基于数据报的服务。 "Socket Server Client 调试工具"作为一个实用工具,其主要功能是帮助开发者快速、直观地测试和调试Socket...
TCP是一种面向连接的、可靠的传输协议,通过三次握手建立连接,并通过确认、重传机制保证数据的可靠传输。在TCP Server中,服务器端会监听特定的端口,等待客户端发起连接请求,一旦接收到请求,就会建立一个连接,...
TCP是一种面向连接的、可靠的传输协议,它确保数据包按照顺序无损地送达。Socket Utility允许用户设置Server的监听端口,以便接收来自客户端的连接。一旦连接建立,双方可以进行双向的数据交换。 相比之下,TCP ...
在TCP/IP协议栈中,Socket接口实现了TCP和UDP两种传输协议,分别用于面向连接和无连接的服务。在本次实验中,我们将主要关注基于TCP的Socket编程。 **2. 创建Socket** 创建Socket首先要选择协议类型,通常是TCP或...
在这个实例中,我们主要关注流式Socket,它提供面向连接、可靠的数据传输服务。 1. **Server端编程** - **创建ServerSocket**: 在服务器端,首先需要创建一个`ServerSocket`对象,指定一个端口号。这个端口是...
本教程将深入探讨如何利用Socket库在Python中实现客户端与服务器之间的简单通信,这涉及到TCP/IP协议中的三次握手和四次挥手过程。 首先,我们来看TCP(传输控制协议)的三次握手。三次握手是为了确保连接的可靠性...
TCP Socket提供面向连接、可靠的数据传输,而UDP Socket则是无连接、不可靠的。 二、Socket通信流程 1. 创建Socket:服务器端通过`socket()`函数创建一个Socket实例,然后绑定到特定的IP地址和端口号,通过`bind()`...
在C-S模式下,通常使用TCP(Transmission Control Protocol)协议,这是一种面向连接、可靠的传输协议,确保数据的无丢失、无重复、按序传输。TCP通过三次握手建立连接,并在数据传输完成后通过四次挥手断开连接。 ...
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它确保了数据的顺序传输和无损传输。在Android中,我们通常使用`java.net.ServerSocket`和`java.net.Socket`类来实现服务器端和客户端的TCP通信。 1. **...
1. TCP(Transmission Control Protocol):面向连接的协议,提供可靠的数据传输服务,确保数据的顺序和完整性。TCP建立连接需要三次握手,断开连接需要四次挥手。 2. UDP(User Datagram Protocol):无连接的协议...
TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输协议,保证了数据包的有序、无损传输。本篇文章将深入探讨如何使用C#进行Socket编程,构建TCP连接的Client和Server。 首先,我们来理解TCP连接的...
TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,广泛应用于互联网中的各种服务,如HTTP、FTP等。而Socket是实现TCP/IP通信的基础,它是进程间通信的一种方式,允许...
流式套接字类似于TCP,提供面向连接、有序且无丢失的服务;而数据报套接字类似于UDP,是无连接的,不保证数据顺序和可靠性。本项目中,由于涉及到的是线程间通信,很可能使用的是流式套接字,因为它提供了一种可靠的...
TCP提供面向连接、可靠的数据传输,而UDP则是一种无连接、不可靠的协议,适用于实时数据传输场景。 在这个"socket的简单实现"中,我们主要关注基于TCP的Socket通信。首先,我们从服务器端开始: 1. **服务器端...
Socket分为流式套接字(SOCK_STREAM,对应TCP)和数据报套接字(SOCK_DGRAM,对应UDP)两种类型,本例中涉及的应该是基于TCP的流式套接字,因为TCP提供了面向连接、可靠的数据传输服务。 2. Socket工作原理: 在TCP...
在TCP/IP协议栈中,Socket主要用于TCP(面向连接)和UDP(无连接)两种传输协议。 `ServerController.c`可能是一个C语言编写的服务器控制程序,它包含了初始化Socket,绑定到特定IP地址和端口号,监听客户端连接,...
TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,它通过三次握手建立连接,确保数据的有序无损传输。在C#中,我们通常使用System.Net.Sockets命名空间下的Socket类来...