当前位置:网站首页>一个初级多线程服务器模型
一个初级多线程服务器模型
2022-06-26 12:32:00 【无聊的阿乐】
一个服务端程序,能与多个客户端进行通信。那么,这个服务端是怎么实现的呢?它就是很常规的多线程服务器。运行平台为VS2015。
1、服务端实现
既然是多线程服务器,那么,这些线程肯定是有明确分工的。主线程来处理网络的连接,而通信线程来处理客户端与服务端的通信。
而且,主线程要负责多个客户端的连接请求,所以不能阻塞主线程哦,因此必须用非阻塞socket.
服务端程序如下:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 100
sockaddr_in addrClient; // 为了让通信线程获取ip
//通信线程
DWORD WINAPI CommThread(LPVOID lp)
{
SOCKET sClient = (SOCKET)(LPVOID)lp;
while (1)
{
char buf[BUF_SIZE] = {
0 };
int retVal = recv(sClient, buf, BUF_SIZE, 0);
if (SOCKET_ERROR == retVal)
{
int err = WSAGetLastError();
if (WSAEWOULDBLOCK == err) // 暂时没有数据
{
Sleep(100);
continue;
}
}
// 输出客户端连接信息
SYSTEMTIME st;
GetLocalTime(&st);//获取本地时间
char sDateTime[100] = {
0 };
sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
printf("%s, The client is [%s:%d]. Msg from client is : %s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf);
char msg[BUF_SIZE] = {
0 };
sprintf_s(msg, "Message received is : %s", buf);
while (1)
{
retVal = send(sClient, msg, strlen(msg), 0); //发送给客户端 ,消息已被接收
if (SOCKET_ERROR == retVal)
{
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK)
{
Sleep(500);
continue;
}
}
break;
}
}
closesocket(sClient);
}
int main()
{
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
SOCKET sServer = socket(AF_INET, SOCK_STREAM, 0);
// 设置套接字为非阻塞模式
int iMode = 1;
ioctlsocket(sServer, FIONBIO, (u_long FAR*) &iMode);
// 设置服务器套接字地址
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(8888);
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));
listen(sServer, 10);
/*TCP 务器端依次调用 socket () bind () listen ()之后,就会监昕指定的 socket 地址 TCP 客户端依次调用 socket() connect()之后就会向 TCP 服务器发送了一个连接请求 TCP 服务器监听到这个请求之后,就会调用 accept()函数取接收请求,这样连接就建立好 之后就可以开始网络IO读写 操作了,*/
printf("Server start...\n");
int addrClientlen = sizeof(addrClient);
while (1)
{
SOCKET sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);
if (INVALID_SOCKET == sClient)
{
int err = WSAGetLastError();
if (WSAEWOULDBLOCK == err) // 无法立即完成非阻塞套接字上的操作
{
Sleep(100);
continue;
}
}
// 创建通信线程
CreateThread(NULL, NULL, CommThread, (LPVOID)sClient, 0, NULL);
}
// 释放套接字
closesocket(sServer);
WSACleanup();
getchar();
return 0;
}
2、客户端实现
我们可以看到,上述服务端的程序需要有主线程和通信线程,而客户端的程序就相对简单了,主线程本身就是通信线程。程序如下:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8888);
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//第二个参数为要连接的服务器的地址
send(sockClient, "hello world", strlen("hello world") + 1, 0);
char recvBuf[100] = {
0 };
recv(sockClient, recvBuf, 100, 0);
printf("%s\n", recvBuf);
while (1);
closesocket(sockClient);
WSACleanup();
return 0;
}
我们编译并运行程序,开启3个客户端进程,分别去连接服务端。实际验证发现,服务端分配了三个通信线程,分别来应对3个客户端,可以正常通信。
由此,我们就实现了多线程服务器,能处理多个客户端的并发连接。这是一个非常初级的服务器模型。
边栏推荐
- HUST网络攻防实践|6_物联网设备固件安全实验|实验三 FreeRTOS-MPU 保护绕过
- Build Pikachu shooting range and introduction
- Mqtt disconnect and reconnect
- 【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
- [redis series] redis learning 16. Redis Dictionary (map) and its core coding structure
- [solved] laravel completes the scheduled job task (delayed distribution task) [execute a user-defined task at a specified time]
- [redis series] redis learning 16. Redis Dictionary (map) and its core coding structure
- VMware虚拟机 桥接模式 无法上网 校园网「建议收藏」
- 我想知道,股票开户有哪些优惠活动?网上开户是否安全么?
- Spark-day01- get started quickly
猜你喜欢

2、 MySQL Foundation

4. N queen problem

Statistical genetics: Chapter 2, the concept of statistical analysis

This executeQuery (SQL) cannot compile classes for JSP. What is the reason?

Matlab programming example: how to count the number of elements in a cell array
![[solved] laravel completes the scheduled job task (delayed distribution task) [execute a user-defined task at a specified time]](/img/13/c2c63333a9e5ac08b339449ea17654.jpg)
[solved] laravel completes the scheduled job task (delayed distribution task) [execute a user-defined task at a specified time]
![[graduation season · advanced technology Er] I remember the year after graduation](/img/e7/8e1dafa561217b77a3e3992977a8ec.png)
[graduation season · advanced technology Er] I remember the year after graduation
女性科学家的流失

Scala problem solving the problem of slow SBT Download

Statistical genetics: Chapter 1, basic concepts of genome
随机推荐
Five trends of member marketing of consumer goods enterprises in the future
Jsonarray and jsonobject of fastjson [easy to understand]
redis通过6379端口无法连接服务器
UDP协议详解[通俗易懂]
Leetcode 78. Subset and 90 Subset II
【毕业季·进击的技术er】忆毕业一年有感
I want to know how the top ten securities firms open accounts? Is online account opening safe?
Scala-day06- pattern matching - Generic
Php+laravel5.7 use Alibaba oss+ Alibaba media to process and upload image / video files
2022 edition of China's medical robot industry investment status investigation and prospect dynamic analysis report
CG骨骼动画
Jmeter响应时间和tps监听器使用教程
Using the methods in the repository to solve practical problems
HUST network attack and defense practice | 6_ IOT device firmware security experiment | Experiment 3 freertos-mpu protection bypass
Measures to support the development of cultural and creative industries in Futian District, Shenzhen
Seven major trends deeply affecting the U.S. consumer goods industry in 2022
PHP laravel+gatewayworker completes im instant messaging and file transfer functions (Chapter 2: explanation of business logic)
Ctfshow web getting started command execution web75-77
Assembly language (7) operation instruction
MySQL optimization - index (what is an index?)