服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++多线程实现TCP服务器端同时和多个客户端通信

C++多线程实现TCP服务器端同时和多个客户端通信

2021-11-08 14:21新西兰做的饭 C/C++

通讯建立后首先由服务器端发送消息,客户端接收消息;接着客户端发送消息,服务器端接收消息,实现交互发送消息。本文主要介绍了C++多线程实现TCP服务器端同时和多个客户端通信,感兴趣的可以了解一下

通讯建立后首先由服务器端发送消息,客户端接收消息;接着客户端发送消息,服务器端接收消息,实现交互发送消息。

服务器同时可以和多个客户端建立连接,进行交互;

在某次交互中,服务器端或某客户端有一方发送"end"即终止服务器与其的通信;服务器还可以继续接收其他客户端的请求,与其他客户端通信。

服务器端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define PORT 65432
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter);
int main()
{
    //初始化winsock2.DLL
    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequested, &wsaData) != 0)
    {
        cout << "加载winsock.dll失败!" << endl;
        return 0;
    }
    //创建套接字
    SOCKET  sock_server;
    if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
    {
        cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
        WSACleanup();
        return 0;
    }
    //绑定端口和Ip
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
    if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof(sockaddr_in)))
    {
        cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_server);
        WSACleanup();
        return 0;
    }
    //将套接字设为监听状态
    listen(sock_server, 0);
    
    //主线程循环接收客户端的连接
    while (1)
    {
        sockaddr_in addrClient;
        int len = sizeof(sockaddr_in);
        //接收成功返回与client通讯的socket
        SOCKET con = accept(sock_server, (SOCKADDR*)&addrClient, &len);
        if (con != INVALID_SOCKET)
        {
            //创建线程 并且传入与client通讯的套接字
            HANDLE hThread = CreateThread(NULL, 0, ThreadFun, (LPVOID)con, 0, NULL);
            CloseHandle(hThread); //关闭对线程的引用
        }
    }
    closesocket(sock_server);
    WSACleanup();
    return 0;
}
//线程通讯部分
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter)
{
    //与客户端通讯 先发送再接收数据
    SOCKET sock = (SOCKET)lpThreadParameter;
    cout << "成功和" << sock << "建立连接!" << endl;
    while (1)
    {
        char msgbuffer[1000];//字符缓冲区
        printf("服务器向%d发送数据:\n", sock);
        cin.getline(msgbuffer, sizeof(msgbuffer));
        int size = send(sock, msgbuffer, sizeof(msgbuffer), 0);//给客户端发送一段信息
        if (strcmp(msgbuffer, "end\0") == 0)
        {
            cout << "关闭和" << sock << "的连接!" << endl;
            return 0;
        }
        if (size == SOCKET_ERROR || size == 0)
        {
            cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
            return 0;
        }
        else cout << "信息发送成功!" << endl;
        
        //接收客户端数据
        msgbuffer[999] = { 0 };
        int ret = recv(sock, msgbuffer, sizeof(msgbuffer), 0);
        if(ret == SOCKET_ERROR || ret == 0)
        {
            cout << sock << "断开了连接!" << endl;
            break;
        }
        else cout << sock << "  说: " << msgbuffer << endl;
    }
    return 0;
}

客户端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
using  namespace std;
#pragma comment(lib, "ws2_32.lib")
#define PORT 65432
int  main()
{
    //初始化winsock2.DLL
    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequested, &wsaData) != 0)
    {
        cout << "加载winsock.dll失败!" << endl;
        return 0;
    }
    //创建套接字
    SOCKET  sock_client;
    if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
    {
        cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
        WSACleanup();
        return 0;
    }
    //连接服务器
    sockaddr_in   addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
    int len = sizeof(sockaddr_in);
    if (connect(sock_client, (SOCKADDR*)&addr, len) == SOCKET_ERROR) {
        cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
        return 0;
    }
    //实现交互部分,客户端先接收后发送数据
    while (1)
    {
        //接收服务端的消息
        char msgbuffer[1000] = { 0 };
        int size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0);
        if (strcmp(msgbuffer, "end\0") == 0)
        {
            cout << "服务器端已经关闭连接!" << endl;
            break;
        }
        if (size < 0)
        {
            cout << "接收信息失败!错误代码:" << WSAGetLastError() << endl;
            break;
        }
        else if (size == 0)
        {
            cout << "对方已经关闭连接" << endl;
            break;
        }
        else cout << "The message from Server:" << msgbuffer << endl;
 
        //从键盘输入一行文字发送给服务器
        msgbuffer[999] =  0 ;
        cout << "从键盘输入发给服务器的信息:" << endl;
        cin.getline(msgbuffer, sizeof(msgbuffer));
        if (strcmp(msgbuffer, "end\0") == 0)
        {
            cout << "关闭连接!" << endl;
            break;
        }
        int ret = send(sock_client, msgbuffer, sizeof(msgbuffer), 0);
        if (ret == SOCKET_ERROR || ret == 0)
        {
            cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
            break;
        }
        else cout << "信息发送成功!" << endl;
    }
    closesocket(sock_client);
    WSACleanup();
    return 0;
}

我们用建立连接时服务器端接收的客户端套接字来唯一标识该客户端。
服务器端可以随时接收客户端的连接并与其进行交互。

运行实例

C++多线程实现TCP服务器端同时和多个客户端通信

实例展示了服务器端和两个客户端通信的运行过程,包括正常交互、交互过程中另一服务器请求建立连接、服务器主动断开连接和客户端主动断开连接等过程。

到此这篇关于C++多线程实现TCP服务器端同时和多个客户端通信 的文章就介绍到这了,更多相关C++ 服务器端和多个客户端通信 内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_45929428/article/details/116709789

延伸 · 阅读

精彩推荐
  • C/C++C++之重载 重定义与重写用法详解

    C++之重载 重定义与重写用法详解

    这篇文章主要介绍了C++之重载 重定义与重写用法详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    青山的青6062022-01-04
  • C/C++C/C++经典实例之模拟计算器示例代码

    C/C++经典实例之模拟计算器示例代码

    最近在看到的一个需求,本以为比较简单,但花了不少时间,所以下面这篇文章主要给大家介绍了关于C/C++经典实例之模拟计算器的相关资料,文中通过示...

    jia150610152021-06-07
  • C/C++深入理解goto语句的替代实现方式分析

    深入理解goto语句的替代实现方式分析

    本篇文章是对goto语句的替代实现方式进行了详细的分析介绍,需要的朋友参考下...

    C语言教程网7342020-12-03
  • C/C++C语言实现电脑关机程序

    C语言实现电脑关机程序

    这篇文章主要为大家详细介绍了C语言实现电脑关机程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    xiaocaidayong8482021-08-20
  • C/C++C语言中炫酷的文件操作实例详解

    C语言中炫酷的文件操作实例详解

    内存中的数据都是暂时的,当程序结束时,它们都将丢失,为了永久性的保存大量的数据,C语言提供了对文件的操作,这篇文章主要给大家介绍了关于C语言中文件...

    针眼_6702022-01-24
  • C/C++学习C++编程的必备软件

    学习C++编程的必备软件

    本文给大家分享的是作者在学习使用C++进行编程的时候所用到的一些常用的软件,这里推荐给大家...

    谢恩铭10102021-05-08
  • C/C++c++ 单线程实现同时监听多个端口

    c++ 单线程实现同时监听多个端口

    这篇文章主要介绍了c++ 单线程实现同时监听多个端口的方法,帮助大家更好的理解和学习使用c++,感兴趣的朋友可以了解下...

    源之缘11542021-10-27
  • C/C++详解c语言中的 strcpy和strncpy字符串函数使用

    详解c语言中的 strcpy和strncpy字符串函数使用

    strcpy 和strcnpy函数是字符串复制函数。接下来通过本文给大家介绍c语言中的strcpy和strncpy字符串函数使用,感兴趣的朋友跟随小编要求看看吧...

    spring-go5642021-07-02