c++下基于windows socket的多线程服务器(基于TCP协议)
之前用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协议)的更多相关文章
- c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)
今天自己编写了一个简单的c++服务器客户端程序,注释较详细,在此做个笔记. windows下socket编程的主要流程可概括如下:初始化ws2_32.dll动态库-->创建套接字-->绑定 ...
- c++下基于windows socket的服务器客户端程序(基于UDP协议)
前天写了一个基于tcp协议的服务器客户端程序,今天写了一个基于UDP协议的,由于在上一篇使用TCP协议的服务器中注释已经较为详细,且许多api的调用是相同的,故不再另外注释. 使用UDP协议需要注意几 ...
- TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现
目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...
- 基于事件的 NIO 多线程服务器--转载
JDK1.4 的 NIO 有效解决了原有流式 IO 存在的线程开销的问题,在 NIO 中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个 CPU 的处 ...
- Linux 高性能服务器编程——TCP协议详解
问题聚焦: 本节从如下四个方面讨论TCP协议: TCP头部信息:指定通信的源端端口号.目的端端口号.管理TCP连接,控制两个方向的数据流 TCP状态转移过程:TCP连接的任意一 ...
- java基础知识回顾之java Socket学习(二)--TCP协议编程
TCP传输(传输控制协议):TCP协议是一种面向连接的,可靠的字节流服务.当客户端和服务器端彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能进行数据的传输.它将一台主机发出的字节流无差错的 ...
- 网络编程----------SOCKET编程实现简单的TCP协议
首先我们须要大致了解TCP的几点知识: 1.TCP的特点:面向连接的可靠性传输 2.TCP的三次握手建立连接和四次挥手释放连接.但为什么TCP要三次握手建立连接呢? 答:由于两次握手无法保证可靠性.若 ...
- TCP/IP协议学习(四) 基于C# Socket的Web服务器---静态资源处理
目录 1. C# Socket通讯 2. HTTP 解析引擎 3. 资源读取和返回 4. 服务器测试和代码下载 Web服务器是Web资源的宿主,它需要处理用户端浏览器的请求,并指定对应的Web资源返回 ...
- linux下一对多socket服务器端多线程泄露问题
线程创建多了,没有释放.导致内存泄露... int main() { int len; int on=1; // pMachList = CreateEmptyLinklist(); DataBase ...
随机推荐
- ccf碰撞的小球
之前的代码有人运行不成功,自己又看了一下是输入变量顺序输入错了,现在是正确答案- #include<stdio.h> struct node{ int x; int dir; }; int ...
- hdu-6397-容斥
Character Encoding Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Oth ...
- Java并发编程(五)JVM指令重排
我是不是学了一门假的java...... 引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果.. ...
- 静态HTML总结
第一章<META>标签: <meta http-equiv=”Content-Type” Content=”text/html;charset=gb2312”>------避免 ...
- SpringBoot添加webapp目录
一.文章简述 使用IDEA工具创建的SpringBoot项目本身是没有webapp目录的.如果我们想要添加webapp目录的话,可以手动添加. 二.操作步骤 1)点击IDEA右上角的Project S ...
- spring boot 入门 使用spring.profiles.active来分区配置
很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用profile在不同的环境 ...
- learning ddr mode reigster set command cycle time tMRD and tMOD
tMRD: tMOD:
- Python pycharm 引入需要使用的包
第一步 第二步 第三步
- asp.net MVC之AuthorizeAttribute浅析
AuthorizeAttribute是asp.net MVC的几大过滤器之一,俗称认证和授权过滤器,也就是判断登录与否,授权与否.当为某一个Controller或Action附加该特性时,没有登录或授 ...
- SQL-38 创建视图
题目描述 针对actor表创建视图actor_name_view,只包含first_name以及last_name两列,并对这两列重新命名,first_name为first_name_v,last_n ...