socket通信参考

参考:https://blog.csdn.net/qq_36025591/article/details/113964442

 

 

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>

// 打印十六进制报文的函数(用户已实现)
void printHexDump(const char *buf, int len)
{
    {
        std::cout << "原始报文(HEX): ";
        for (int i = 0; i < len; ++i)
        {
            {
                printf("%02X ", (unsigned char)buf[i]);
                if ((i + 1) % 16 == 0)
                    std::cout << std::endl;
            }
        }
        std::cout << "\n------------------------" << std::endl;
    }
}

int main()
{
    {
        // 1. 创建 TCP socket,AF_INET是ipv4,SOCK_STREAM是tcp协议
        // 1.1 成功返回文件描述符,失败返回-1
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
        {
            {
                perror("socket 创建失败");
                return -1;
            }
        }

        // 2. 给上面的socket绑定并监听(示例绑定到 0.0.0.0:6666)
        // 2.1  (sockaddr *)&server_addr解释:
        //      先获取server_addr的指针(即&server_addr),再强制转换成sockaddr_in的指针(即(sockaddr *)&server_addr)
        // 3 成功返回0
        sockaddr_in server_addr{};
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(6666);
        server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");

        if (bind(sockfd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0)
        {
            {
                perror("bind 失败");
                close(sockfd);
                return -1;
            }
        }

        /**
         * 建立监听
         * 参数1:监听的server端socket套接字
         * 参数2:最大允许等待挂起的连接数
         * 成功返回0,失败返回-1
         *
         */
        listen(sockfd, 5);

        /**
         * 说明:
         * 1.TCP服务端依次调用socket()、bind()、listen()之后,就会监听指定的客户端socket地址了
         * 2.TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求
         * 3.TCP服务器监听到这个请求之后,就会调用accept()函数去接收请求,这样连接就建立好了。
         * 4.之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作,还是通过socket套接字进行。
         */

        // 3. 接受客户端连接
        /**
         * 作用:创建一个新的的socket套接字,并返回一个socket描述字。
         * 第一个参数为服务器的socket描述字
         * 第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址
         * 第三个参数为客户端协议地址的长度
         * 如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字(newsocket),代表与返回客户的TCP连接。
         * accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。两个套接字不一样。
         * accept 默认是阻塞,意思就是会一直等待直到有客户端连接过来。
         */
        sockaddr_in client_addr{};
        socklen_t client_len = sizeof(client_addr);
        int client_sock = accept(sockfd, (sockaddr *)&client_addr, &client_len);
        if (client_sock < 0)
        {
            {
                perror("accept 失败");
                close(sockfd);
                return -1;
            }
        }

        // 4. 使用 ioctl 获取待读取数据大小
        int bytes_available = 0;
        if (ioctl(client_sock, FIONREAD, &bytes_available) < 0)
        {
            {
                perror("ioctl 失败");
                close(client_sock);
                close(sockfd);
                return -1;
            }
        }

        // 5. 读取报文并打印
        int BUFFER_SIZE = 1024;
        char buffer[BUFFER_SIZE]; // BUFFER_SIZE 建议设为 4096 或更大
        ssize_t recv_len = recv(client_sock, buffer, bytes_available, 0);
        if (recv_len > 0)
        {
            {
                printHexDump(buffer, recv_len);
            }
        }
        else
        {
            {
                std::cerr << "接收错误或连接关闭" << std::endl;
            }
        }

        // 6. 关闭连接
        close(client_sock);
        close(sockfd);
        return 0;
    }
}

 

posted @ 2025-06-28 16:51  小小仓鼠  阅读(15)  评论(0)    收藏  举报