之前用c++实现过基于windows socket的单线程TCP服务器(http://www.cnblogs.com/jzincnblogs/p/5170230.html),今天实现了一个多线程的版本,可以接受多个客户端的请求,原理与之前的单线程版本相似,只是在多线程版本中主线程用于监测客户端请求,每当有新客户端请求连接,主线程便新开一个线程用户处理客户端的请求。代码如下:

  头文件:

 #ifndef SERVER_H
#define SERVER_H #include <Winsock2.h>
#include <windows.h> #pragma comment (lib, "ws2_32.lib") #define IP_BUF_SIZE 129 class Server
{
public:
Server();
~Server();
Server(const Server &) = delete;
Server & operator=(const Server &) = delete;
void WaitForClient();
private:
WORD winsock_ver;
WSADATA wsa_data;
SOCKET sock_svr;
SOCKET sock_clt;
HANDLE h_thread;
SOCKADDR_IN addr_svr;
SOCKADDR_IN addr_clt;
int ret_val;
int addr_len;
char buf_ip[IP_BUF_SIZE];
}; #endif

  函数定义:

 #include "server.h"
#include <iostream>
#include <WS2tcpip.h> using std::cerr;
using std::cout;
using std::endl; #define SERVER_PORT 5000
#define MSG_BUF_SIZE 1024 Server::Server()
{
cout << "Initializing server...\n";
//
winsock_ver = MAKEWORD(, );
addr_len = sizeof(SOCKADDR_IN);
addr_svr.sin_family = AF_INET;
addr_svr.sin_port = ::htons(SERVER_PORT);
addr_svr.sin_addr.S_un.S_addr = ADDR_ANY;
memset(buf_ip, 0, IP_BUF_SIZE);
//
ret_val = ::WSAStartup(winsock_ver, &wsa_data);
if (ret_val != )
{
cerr << "WSA failed to start up!Error code: " << ::WSAGetLastError() << "\n";
system("pause");
exit();
}
cout << "WSA started up successfully...\n";
//
sock_svr = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock_svr == INVALID_SOCKET)
{
cerr << "Failed to create server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit();
}
cout << "Server socket created successfully...\n";
//
ret_val = ::bind(sock_svr, (SOCKADDR*)&addr_svr, addr_len);
if (ret_val != )
{
cerr << "Failed to bind server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit();
}
cout << "Server socket bound successfully...\n";
//
ret_val = ::listen(sock_svr, SOMAXCONN);
if (ret_val == SOCKET_ERROR)
{
cerr << "Server socket failed to listen!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit();
}
cout << "Server socket started to listen...\n";
//
cout << "Server started successfully..." << endl;
} Server::~Server()
{
::closesocket(sock_svr);
::closesocket(sock_clt);
::WSACleanup();
cout << "Socket closed..." << endl;
} DWORD WINAPI CreateClientThread(LPVOID lpParameter);
//
void Server::WaitForClient()
{
while (true)
{
sock_clt = ::accept(sock_svr, (SOCKADDR*)&addr_clt, &addr_len);
if (sock_clt == INVALID_SOCKET)
{
cerr << "Failed to accept client!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit();
}
::InetNtop(addr_clt.sin_family, &addr_clt, buf_ip, IP_BUF_SIZE);
cout << "A new client connected...IP address: " << buf_ip << ", port number: " << ::ntohs(addr_clt.sin_port) << endl;
h_thread = ::CreateThread(nullptr, , CreateClientThread, (LPVOID)sock_clt, , nullptr);
if (h_thread == NULL)
{
cerr << "Failed to create a new thread!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit();
}
::CloseHandle(h_thread);
}
} DWORD WINAPI CreateClientThread(LPVOID lpParameter)
{
SOCKET sock_clt = (SOCKET)lpParameter;
char buf_msg[MSG_BUF_SIZE];
int ret_val = ;
int snd_result = ;
do
{
memset(buf_msg, 0, MSG_BUF_SIZE);
ret_val = ::recv(sock_clt, buf_msg, MSG_BUF_SIZE, );
if (ret_val > )
{
if (strcmp(buf_msg, "exit") == )
{
cout << "Client requests to close the connection..." << endl;
break;
}
cout << "Message received: " << buf_msg << endl;
snd_result = ::send(sock_clt, buf_msg, MSG_BUF_SIZE, );
if (snd_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return ;
}
}
else if (ret_val == )
{
cout << "connection closed..." << endl;
}
else
{
cerr << "Failed to receive message from client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return ;
}
} while (ret_val > );
//
ret_val = ::shutdown(sock_clt, SD_SEND);
if (ret_val == SOCKET_ERROR)
{
cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return ;
}
return ;
}

  程序入口:

 #include "server.h"

 int main()
{
Server svr;
svr.WaitForClient();
system("pause");
return ;
}

c++下基于windows socket的多线程服务器(基于TCP协议)的更多相关文章

  1. c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)

    今天自己编写了一个简单的c++服务器客户端程序,注释较详细,在此做个笔记. windows下socket编程的主要流程可概括如下:初始化ws2_32.dll动态库-->创建套接字-->绑定 ...

  2. c++下基于windows socket的服务器客户端程序(基于UDP协议)

    前天写了一个基于tcp协议的服务器客户端程序,今天写了一个基于UDP协议的,由于在上一篇使用TCP协议的服务器中注释已经较为详细,且许多api的调用是相同的,故不再另外注释. 使用UDP协议需要注意几 ...

  3. TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现

    目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...

  4. 基于事件的 NIO 多线程服务器--转载

    JDK1.4 的 NIO 有效解决了原有流式 IO 存在的线程开销的问题,在 NIO 中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个 CPU 的处 ...

  5. Linux 高性能服务器编程——TCP协议详解

    问题聚焦:     本节从如下四个方面讨论TCP协议:     TCP头部信息:指定通信的源端端口号.目的端端口号.管理TCP连接,控制两个方向的数据流     TCP状态转移过程:TCP连接的任意一 ...

  6. java基础知识回顾之java Socket学习(二)--TCP协议编程

    TCP传输(传输控制协议):TCP协议是一种面向连接的,可靠的字节流服务.当客户端和服务器端彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能进行数据的传输.它将一台主机发出的字节流无差错的 ...

  7. 网络编程----------SOCKET编程实现简单的TCP协议

    首先我们须要大致了解TCP的几点知识: 1.TCP的特点:面向连接的可靠性传输 2.TCP的三次握手建立连接和四次挥手释放连接.但为什么TCP要三次握手建立连接呢? 答:由于两次握手无法保证可靠性.若 ...

  8. TCP/IP协议学习(四) 基于C# Socket的Web服务器---静态资源处理

    目录 1. C# Socket通讯 2. HTTP 解析引擎 3. 资源读取和返回 4. 服务器测试和代码下载 Web服务器是Web资源的宿主,它需要处理用户端浏览器的请求,并指定对应的Web资源返回 ...

  9. linux下一对多socket服务器端多线程泄露问题

    线程创建多了,没有释放.导致内存泄露... int main() { int len; int on=1; // pMachList = CreateEmptyLinklist(); DataBase ...

随机推荐

  1. csu oj 1342: Double

    Description 有一个由M个整数组成的序列,每次从中随机取一个数(序列中每个数被选到的概率是相等的)累加,一共取N次,最后结果能被3整除的概率是多少? Input 输入包含多组数据.     ...

  2. DBWritable的使用

    首先导入mysql连接驱动jar包 或者maven模式下在pom.xml文件中追加: <dependency> <groupId>mysql</groupId> & ...

  3. python-flask-session和scoped_session区别

    scoped_session from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from sql ...

  4. WCF开发实战系列二:使用IIS发布WCF服务 转

    转 http://www.cnblogs.com/poissonnotes/archive/2010/08/28/1811141.html 上一篇中,我们创建了一个简单的WCF服务,在测试的时候,我们 ...

  5. 【LeetCode】成对交换节点

    e.g. 给定链表 1->2->3->4,返回 2->1->4->3 的头节点. 我写了个常见的从头节点遍历,少量的奇数个或偶数个数据都能成功重新排列.但链表过长时 ...

  6. Git clone 常见用法

    二 克隆Git仓库     1.1 从远程仓库中克隆整个代码仓库 mkdir Demo //在当前路径下新建一个文件夹,用来存放将要拉取的整个代码库 cd Demo           //进入这个文 ...

  7. php 循环数组问题

    $a = array('abe','ben','cam'); //foreach遍历数组时,实际上是遍历的数组的一个拷贝,并且在开始遍历之前会把指针指向拷贝的开始:,根据cow机制,写时,重新复制一份 ...

  8. utf8mb4与utf8的区别

    今天在测试小程序保存表情时,数据库插入数据时报错ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect string value: '\xF0\x9F\x98\x8 ...

  9. Qt绘制文本一

    QPainterPath,使用 drawText且设置字体,再使用painter.drawText方式 效果图: void WgtText::paintEvent(QPaintEvent *event ...

  10. php常见问题-foreach和引用造成的问题。

    结论:  foreach($arr as &$v) 类似这样的引用循环, 脚本语言需要注意,再次使用 $v时,他还指向原来的引用.会产生问题. unset($v)可以解除引用. 所以循环引用过 ...