当前位置: 首页 > news >正文

【C++网络编程】第2篇:简单的TCP服务器与客户端

一、TCP通信流程回顾

1. 服务器端流程

1. 创建Socket → socket()
2. 绑定地址和端口 → bind()
3. 开始监听 → listen()
4. 接受客户端连接 → accept()
5. 接收/发送数据 → recv()/send()
6. 关闭连接 → closesocket()

2. 客户端流程

1. 创建Socket → socket()
2. 连接服务器 → connect()
3. 发送/接收数据 → send()/recv()
4. 关闭连接 → closesocket()

二、实现TCP服务器(Echo示例)​

1. 完整代码

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib")  // 自动链接Winsock库

#include <ctype.h>
#include <limits.h>


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

    // 2. 创建Socket
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "Socket creation failed: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    // 3. 绑定地址和端口
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    inet_pton(AF_INET,"127.0.0.1", &(serverAddr.sin_addr.s_addr));  // 本地回环地址
    serverAddr.sin_port = htons(8080);                    // 监听8080端口

    if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Bind failed: " << WSAGetLastError() << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    // 4. 开始监听
    if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
        std::cerr << "Listen failed: " << WSAGetLastError() << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    std::cout << "Server started. Listening on 127.0.0.1:8080..." << std::endl;

    // 5. 接受客户端连接
    sockaddr_in clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrLen);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Accept failed: " << WSAGetLastError() << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    // 6. 接收并回传数据(Echo)
    char buffer[1024];
    int bytesReceived;
    do {
        bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
        if (bytesReceived > 0) {
            send(clientSocket, buffer, bytesReceived, 0);  // 原样返回数据
      
            std::cout << "Echoed " << bytesReceived << " bytes. Datas:" << std::string(buffer, bytesReceived) << std::endl;
        }
    } while (bytesReceived > 0);

    // 7. 清理资源
    closesocket(clientSocket);
    closesocket(serverSocket);
    WSACleanup();
    return 0;
}

三、实现TCP客户端

1. 完整代码

#include <iostream>
#include <string>
#include <winsock2.h>
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib")

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

    // 2. 创建Socket
    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Socket creation failed: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    // 3. 连接服务器
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr.s_addr));
    serverAddr.sin_port = htons(8080);

    if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Connect failed: " << WSAGetLastError() << std::endl;
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }

    std::cout << "Connected to server. Enter messages to send (type 'exit' to quit):" << std::endl;

    // 4. 发送和接收数据
    std::string message;
    char buffer[1024];
    do {
        std::getline(std::cin, message);
        if (message == "exit") break;

        // 发送数据
        send(clientSocket, message.c_str(), message.size(), 0);

        // 接收回显
        int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
        if (bytesReceived > 0) {
            std::cout << "Server echoed: " << std::string(buffer, bytesReceived) << std::endl;
        }
    } while (true);

    // 5. 清理资源
    closesocket(clientSocket);
    WSACleanup();
    return 0;
}

四、关键代码解析

1. socket() 参数说明

  • AF_INET:IPv4地址族。
  • SOCK_STREAM:面向流的传输协议(TCP)。
  • IPPROTO_TCP:明确指定TCP协议(可填0自动选择)。

2. bind() 的地址设置

  • INADDR_ANY:若服务器需要监听所有网卡,可改为:
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);  // 监听所有网卡

3. listen() 的待处理队列

  • SOMAXCONN:系统允许的最大挂起连接数(Windows默认为200)。

4. accept() 的阻塞特性

  • 若无客户端连接,accept()会一直阻塞,直到新连接到达。

五、运行与测试

1. 客户端输入/输出

在这里插入图片描述

2. 服务器端输出

在这里插入图片描述

相关文章:

  • 【华为Pura先锋盛典】华为Pura X“阔折叠”手机发布:首次全面搭载HarmonyOS 5
  • 常用的 MyBatis 标签及其作用
  • Java EE(14)——网络原理——UDPTCP数据报的结构
  • C语言程序设计第四版-课本习题(第六章-循环控制结构)
  • 星越L_陡坡缓降使用讲解
  • 双系统下Linux挂载Windows硬盘失败
  • centos 7 部署ftp 基于匿名用户
  • 详解“二分”系列算法
  • 织梦DedeCMS让CKeditor编辑模板文件的方法(默认源码模式编辑)
  • Java-servlet(七)详细讲解Servlet注解
  • 音视频框架详解
  • 第十四次CCF-CSP认证(含C++源码)
  • Python——MySQL数据库编程
  • DeepSeek API keys本地调用 [python]
  • 【AI知识】在 PyTorch 中设计和实现一个完整的模型训练和优化流程
  • C语言 数据结构【动态顺序表】详解
  • 表格标题竖直
  • IP地址结构体与字符串转换函数详解
  • 基于RT-thread使用STM32F407驱动LCD屏幕
  • 【HCIA-晴天老师】15-VLAN的Hybrid配置笔记
  • 白宫启动“返乡计划” ,鼓励非法移民自愿离开美国
  • 马上评丨规范隐藏式车门把手,重申安全高于酷炫
  • 中国证监会印发2025年度立法工作计划
  • 长江画派创始人之一、美术家鲁慕迅逝世,享年98岁
  • 海关总署统计分析司司长:4月进出口增速较一季度加快4.3个百分点
  • 重温经典|《南郭先生》:不模仿别人,不重复自己