之前用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. Wannafly挑战赛23B游戏

    https://www.nowcoder.com/acm/contest/161/B 题意:两个人van游戏,n堆石子,每次只能取这堆石子数目的因子个数,没得取的人输,问第一个人的必胜策略有多少种 题 ...

  2. ACM基础(一)

    比较大的数组应尽量声明在main函数外,否则程序可能无法运行. C语言的数组并不是“一等公民”,而是“受歧视”的.例如,数组不能够进行赋值操作: 在程序3-1中,如果声明的是“int a[maxn], ...

  3. hadoopMR自定义输入格式

    输入格式 1.输入分片与记录  2.文件输入  3.文本输入  4.二进制输入  5.多文件输入  6.数据库格式输入 详细的介绍:https://blog.csdn.net/py_123456/ar ...

  4. Oracle11g ADG环境实施文档-1204

    Oracle11g adg 环境搭建实施手册-1204 2017年8月30日 9:16 11g adg 环境搭建实施手册-0824 2017年8月24日 10:18 ################# ...

  5. IDEA 自动生成 serialVersionUID 的设置

    打开File菜单,选择Settings选项,打开Settings设置对话框:左边树形目录,打开Editor>Inspections

  6. 跳转到页面的某个anchor

    var loc = document.location.toString().split('#')[0]; document.location = loc + '#' + anchor;

  7. 一、集合框架(HashMap和Hashtable的区别)

    一.HashMap和Hashtable 都实现了Map接口,都是以key-value形式保存数据. 区别一: HashMap可以存放null Hashtable不能存放null 区别二: HashMa ...

  8. sublime ctags跳转函数使用

    sublime 点击某函数 按F12可以查到相关函数文件 正题: 1.下载ctags客户端文件 http://prdownloads.sourceforge.net/ctags/ctags58.zip ...

  9. volatile原理解析

    Java并发编程:volatile关键字解析 volatile 有序性.可见性 volatile可以保证一定程度上有序性,即volatile前面的代码先于后面的代码先执行. 但是前.后代码,各自里面的 ...

  10. MySQL中的文件

    查看数据目录: select @@datadir; 共享表空间: ibdata1 Redo log file:ib_logfile0, ib_logfile1 二进制日志:需要配置参数 server- ...