C++实现网络聊天室-作业-visual-studio

    先叠甲,只能实现客户端到服务端一对一聊天,要支持多人的话,得使用多线程,这个答主还不会,可以去问问gpt帮你添加一下这个功能。

    目前是基于visual studio 2022软件,仅支持终端通话,想要获得精美的图形化界面,问gpt,或者用Qt去写,这个只是一个小作业,仅供初学者参考,或者应付学校的计网作业,想要写一个大项目,拥有完整的功能的话,推荐去b站找找,咱这你懂的,开vip去吧

一、项目简介

我会给出代码思路,供大家写项目实验报告书的,也方便大家理解代码怎么来的。

代码分为两个部分,分别为服务端(Server)客户端(Client),注意,大家需要在vs中创建两个项目,分别来新建空项目,可以直接粘贴代码,看好多答主直接给代码的,又不教怎么弄,运行还全是报错😓😓  分别新建两个cpp文件,server.cpp 和 client.cpp

二、代码部分讲解

以下是对服务端和客户端代码的逐步解释,帮助你理解代码的功能,便于讲解和复现。


(一)服务端代码讲解

1. 初始化 Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    std::cerr << "WSAStartup failed.\n";
    return 1;
}
  • Winsock 是 Windows 网络编程的核心库WSAStartup 初始化网络功能,MAKEWORD(2, 2) 指定使用 Winsock 2.2 版本。
  • 如果初始化失败,会返回错误。

2. 创建服务器套接字
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  • AF_INET:指定使用 IPv4。
  • SOCK_STREAM:使用面向连接的 TCP 协议。
  • IPPROTO_TCP:明确使用 TCP 协议。

如果返回值是 INVALID_SOCKET,说明套接字创建失败。


3. 绑定服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY; // 接收来自任何 IP 的连接
serverAddr.sin_port = htons(PORT);      // 指定监听端口

bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
  • sin_family:设置协议族(IPv4)。
  • sin_addr.s_addr:指定可以接收任何 IP 的连接。
  • sin_port:通过 htons 转换为网络字节序。

bind:将套接字和服务器地址绑定起来。


4. 开始监听
listen(serverSocket, 5);
  • listen 函数使服务器进入监听状态。
  • 参数 5 表示最多能排队的连接数。

5. 接受客户端连接
clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
  • accept 等待客户端连接,当有客户端连接时,返回一个新的 clientSocket,用于与该客户端通信。

6. 通信逻辑
int bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE, 0);
send(clientSocket, reply.c_str(), reply.length(), 0);
  • recv:接收客户端发送的数据,存入 buffer
  • send:将数据发送回客户端。

循环监听直到客户端断开连接。


7. 清理资源
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
  • closesocket:关闭套接字,释放资源。
  • WSACleanup:清理 Winsock 库。

(二)客户端代码讲解

1. 初始化 Winsock
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
  • 和服务端一样,初始化 Winsock。

2. 创建客户端套接字
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  • 创建 TCP 套接字,用于与服务端通信。

3. 连接到服务器
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
serverAddr.sin_port = htons(PORT);

connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
  • inet_addr:将服务器的 IP 地址(字符串)转换为 in_addr 格式。
  • connect:尝试连接到指定 IP 和端口的服务器。

4. 通信逻辑
send(clientSocket, message.c_str(), message.length(), 0);
recv(clientSocket, buffer, BUFFER_SIZE, 0);
  • send:将用户输入的数据发送给服务端。
  • recv:接收服务端返回的消息并打印。

5. 清理资源
closesocket(clientSocket);
WSACleanup();
  • 关闭套接字,释放 Winsock 资源。

运行代码的步骤

  1. 启动服务端
    • 先运行服务端程序,等待客户端连接。
  2. 启动客户端
    • 在同一台电脑或局域网中运行客户端程序,连接到服务端。
    • 输入消息,观察双方通信。

(三)运行截图

三、原代码(可以直接粘贴)

如果有报错,先问gpt,21世纪了要学会自己解决问题了,当然只要答主没毕业,理论上一直会在,最多隔一两天回你😀😀

1、服务端(server.cpp)

#include <iostream>
#include <winsock2.h>
#include <string>

#pragma comment(lib, "ws2_32.lib") // 链接 Winsock 库

#define PORT 12345
#define BUFFER_SIZE 1024

int main() {
    WSADATA wsaData;
    SOCKET serverSocket, clientSocket;
    sockaddr_in serverAddr, clientAddr;
    char buffer[BUFFER_SIZE];

    // 初始化 Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "WSAStartup failed.\n";
        return 1;
    }

    // 创建套接字
    serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "Socket creation failed.\n";
        WSACleanup();
        return 1;
    }

    // 设置服务器地址和端口
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY; // 监听所有 IP 地址
    serverAddr.sin_port = htons(PORT);

    // 绑定套接字
    if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Bind failed.\n";
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    // 开始监听
    if (listen(serverSocket, 5) == SOCKET_ERROR) {
        std::cerr << "Listen failed.\n";
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }
    std::cout << "Server is listening on port " << PORT << "...\n";

    // 接受客户端连接
    int clientAddrSize = sizeof(clientAddr);
    clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Accept failed.\n";
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }
    std::cout << "Client connected.\n";

    // 通信
    while (true) {
        memset(buffer, 0, BUFFER_SIZE);
        int bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE, 0);
        if (bytesReceived <= 0) {
            std::cout << "Connection closed by client.\n";
            break;
        }
        std::cout << "Client: " << buffer << "\n";

        std::string reply;
        std::cout << "Server: ";
        std::getline(std::cin, reply);
        send(clientSocket, reply.c_str(), reply.length(), 0);
    }

    // 关闭套接字
    closesocket(clientSocket);
    closesocket(serverSocket);
    WSACleanup();
    return 0;
}

2、客户端(client.cpp)

#include <iostream>
#include <winsock2.h>
#include <string>

#pragma comment(lib, "ws2_32.lib") // 链接 Winsock 库

#define SERVER_IP "127.0.0.1" // 服务器 IP 地址
#define PORT 12345
#define BUFFER_SIZE 1024

int main() {
    WSADATA wsaData;
    SOCKET clientSocket;
    sockaddr_in serverAddr;
    char buffer[BUFFER_SIZE];

    // 初始化 Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "WSAStartup failed.\n";
        return 1;
    }

    // 创建套接字
    clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Socket creation failed.\n";
        WSACleanup();
        return 1;
    }

    // 设置服务器地址和端口
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
    serverAddr.sin_port = htons(PORT);

    // 连接到服务器
    if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Connection to server failed.\n";
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }
    std::cout << "Connected to server.\n";

    // 通信
    while (true) {
        std::string message;
        std::cout << "Client: ";
        std::getline(std::cin, message);
        send(clientSocket, message.c_str(), message.length(), 0);

        memset(buffer, 0, BUFFER_SIZE);
        int bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE, 0);
        if (bytesReceived <= 0) {
            std::cout << "Connection closed by server.\n";
            break;
        }
        std::cout << "Server: " << buffer << "\n";
    }

    // 关闭套接字
    closesocket(clientSocket);
    WSACleanup();
    return 0;
}

注意!!

某些编译器会认为client中的引用链接库错误,给出警告:

点击编译器中的调试,再点击调试属性

进入页面后

点击c/c++,将右侧的SDL 检查 改为否,禁止弹出警告,即可无报错运行

理论上现在你就可以直接运行了,如果觉得还不错,麻烦各位看官老爷点个赞呗🙏🙏

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值