今天给程序加入了socket通讯

该代码示例展示了如何在Windows和Linux环境下使用socket进行网络通信,接收type16格式的字符串。在Windows中,它涉及WSAStartup和WSACleanup等函数;而在Linux中,使用的是socket、connect、recv等系统调用。程序处理接收到的数据,提取特定格式的字段并存储到一个受保护的数据队列中。
摘要由CSDN通过智能技术生成

之前连接的是雷达,发送的是string类型字符串,现在需要接收type16类型字符串

windows下的socket接收type16类型的字符串

这里我封装了两个函数,receiveFromServer用于通信,extractSubstring用于截取通信字段(截取02开头到03中间的信号)

//调用socket连接 接收信号以2开头3结尾中间的type16进制数据
std::string extractSubstring(const std::string& input) {
    std::string str_sub;
    std::string str = input;
    str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); //删除字符串中的空格 02 46 03 > 024603
    std::string fieldValue;
    std::string result;

    for (size_t i = 0; i < str.length(); i += 2) {
        fieldValue = str.substr(i, 2);
        str_sub = str_sub + fieldValue;
        if (str_sub.substr(0, 2) != "02") {
            str_sub = "";
        }
        if (str_sub.substr(0, 2) == "02" && str_sub.substr(str_sub.length() - 2) == "03") {
            if (str_sub.substr(2, 2) == "4e" ||
                str_sub.substr(2, 2) == "44" ||
                str_sub.substr(2, 2) == "43" ||
                str_sub.substr(2, 2) == "53" ||
                str_sub.substr(2, 2) == "54")
            {
                result += str_sub + "\n";
            }
            str_sub = "";
        }
    }
    return result;
}

std::mutex data_mutex;   // 数据锁
std::deque<std::string> data_queue;  // 数据队列

void str_socket_1(std::string ip, int ip_id) {
    // 初始化Winsock库
    WSADATA wsaData;
    int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (err != 0)
    {
        std::cout << "WSAStartup failed with error: " << err << std::endl;
        return;
    }

    // 创建套接字
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET)
    {
        std::cout << "socket failed with error: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return;
    }

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

    // 连接到服务器 
    int ret = connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (ret == SOCKET_ERROR)
    {
        std::cout << "connect failed with error: " << WSAGetLastError() << std::endl;
        closesocket(sock);
        WSACleanup();
        return;
    }

    // 循环接收数据
    while (true) {
        // 从服务器接收数据
        unsigned char recvData[32];
        ret = recv(sock, (char*)recvData, 32, 0);
        if (ret == SOCKET_ERROR)
        {
            std::cout << "recv failed with error: " << WSAGetLastError() << std::endl;
            break;
        }
        else
        {
            std::stringstream ss;
            for (int i = 0; i < ret; i += 2)
            {
                uint16_t value = (uint16_t)(recvData[i] << 8) | recvData[i + 1];
                ss << std::hex << std::setfill('0') << std::setw(4) << value << " ";
            }

            // 处理接收到的数据
            std::string str_sub_1 = extractSubstring(ss.str());
            {
                std::lock_guard<std::mutex> lock(data_mutex);
                data_queue.push_front(str_sub_1);
                if (data_queue.size() > 5) {
                    data_queue.pop_back();  // 删除队列末
                }
            }
        }
    }

    // 关闭套接字和Winsock库
    closesocket(sock);
    WSACleanup();
}

这里在windows下测试完成后需要转linux

这里是linux版本的socket 可以看到变更了头文件以及细微参数的变更 整体与windows都差不多

#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sstream>
#include <iomanip>

std::deque<std::string> data_queue;  // 数据队列

//创建一个端口反复接收字段
void str_socket_1(std::string ip, int ip_id) {
    // 创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        return;
    }

    // 设置服务器地址
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());
    serverAddr.sin_port = htons(ip_id);

    // 连接到服务器
    int ret = connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if (ret == -1) {
        perror("connect");
        close(sock);
        return;
    }

    // 循环接收数据
    while (true) {
        // 从服务器接收数据
        unsigned char recvData[32];
        ret = recv(sock, recvData, sizeof(recvData), 0);
        if (ret == -1) {
            perror("recv");
            break;
        }
        else if (ret == 0) {
            std::cout << "Connection closed by the server." << std::endl;
            break;
        }
        else {
            std::stringstream ss;
            for (int i = 0; i < ret; i += 2) {
                uint16_t value = (uint16_t)(recvData[i] << 8) | recvData[i + 1];
                ss << std::hex << std::setfill('0') << std::setw(4) << value << " ";
            }

            // 处理接收到的数据
            std::string str_sub_1 = extractSubstring(ss.str());
            {
                std::lock_guard<std::mutex> lock(data_mutex);
                data_queue.push_front(str_sub_1);
                if (data_queue.size() > 5) {
                    data_queue.pop_back();  // 删除队列末尾的数据
                }
            }
        }
    }

    // 关闭套接字
    close(sock);
}

以下是一个简单的 C++ 实现的即时通讯程序,包含私聊、群聊和发送文件功能,使用了 socket 编程和多线程技术。 ``` #include <iostream> #include <string> #include <vector> #include <thread> #include <mutex> #include <fstream> #include <winsock2.h> using namespace std; const int MAX_CLIENTS = 10; const int BUFFER_SIZE = 1024; struct Client { SOCKET socket; string name; }; vector<Client> clients; mutex mtx; void broadcast(string message, SOCKET sender = INVALID_SOCKET) { mtx.lock(); for (auto& client : clients) { if (client.socket != sender) { send(client.socket, message.c_str(), message.size() + 1, 0); } } mtx.unlock(); } void send_file(SOCKET receiver, string file_path) { ifstream file(file_path, ios::binary); if (!file) { cerr << "Failed to open file: " << file_path << endl; return; } file.seekg(0, ios::end); int file_size = file.tellg(); char* buffer = new char[file_size]; file.seekg(0, ios::beg); file.read(buffer, file_size); file.close(); send(receiver, (char*)&file_size, sizeof(file_size), 0); send(receiver, buffer, file_size, 0); delete[] buffer; } void handle_client(SOCKET client_socket) { char buffer[BUFFER_SIZE]; int bytes_received; string name; while (true) { bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0); if (bytes_received == SOCKET_ERROR || bytes_received == 0) { cerr << "Client disconnected." << endl; break; } string message(buffer, bytes_received); if (message.substr(0, 5) == "/name") { name = message.substr(6); cout << "Client connected: " << name << endl; broadcast(name + " has joined the chat.", client_socket); Client new_client = { client_socket, name }; mtx.lock(); clients.push_back(new_client); mtx.unlock(); } else if (message.substr(0, 6) == "/whisp") { size_t pos = message.find(' '); if (pos == string::npos) { continue; } string receiver_name = message.substr(7, pos - 7); string private_message = message.substr(pos + 1); for (auto& client : clients) { if (client.name == receiver_name) { send(client.socket, private_message.c_str(), private_message.size() + 1, 0); break; } } } else if (message.substr(0, 6) == "/file ") { size_t pos = message.find(' '); if (pos == string::npos) { continue; } string receiver_name = message.substr(7, pos - 7); string file_path = message.substr(pos + 1); for (auto& client : clients) { if (client.name == receiver_name) { send_file(client.socket, file_path); break; } } } else { cout << name << ": " << message << endl; broadcast(name + ": " + message, client_socket); } } mtx.lock(); for (auto it = clients.begin(); it != clients.end(); ++it) { if (it->socket == client_socket) { cout << "Client disconnected: " << it->name << endl; broadcast(it->name + " has left the chat.", client_socket); clients.erase(it); break; } } mtx.unlock(); closesocket(client_socket); } int main() { WSADATA wsa_data; int result = WSAStartup(MAKEWORD(2, 2), &wsa_data); if (result != 0) { cerr << "WSAStartup failed with error: " << result << endl; return -1; } SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server_socket == INVALID_SOCKET) { cerr << "socket failed with error: " << WSAGetLastError() << endl; WSACleanup(); return -1; } sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(12345); server_addr.sin_addr.s_addr = INADDR_ANY; result = bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)); if (result == SOCKET_ERROR) { cerr << "bind failed with error: " << WSAGetLastError() << endl; closesocket(server_socket); WSACleanup(); return -1; } result = listen(server_socket, SOMAXCONN); if (result == SOCKET_ERROR) { cerr << "listen failed with error: " << WSAGetLastError() << endl; closesocket(server_socket); WSACleanup(); return -1; } cout << "Waiting for clients to connect..." << endl; while (true) { SOCKET client_socket = accept(server_socket, NULL, NULL); if (client_socket == INVALID_SOCKET) { cerr << "accept failed with error: " << WSAGetLastError() << endl; closesocket(server_socket); WSACleanup(); return -1; } thread t(handle_client, client_socket); t.detach(); } closesocket(server_socket); WSACleanup(); return 0; } ``` 在此程序中,我们使用了一个结构体 `Client` 来保存每个客户端的信息,包括套接字和名称。使用 `vector<Client>` 来保存所有连接的客户端。使用 `mutex` 来保证多线程安全。 `broadcast` 函数用于向除了发送者之外的所有客户端广播消息,可以选择不指定发送者。`send_file` 函数用于将文件发送给指定客户端。 在 `handle_client` 函数中,首先接收客户端发送的消息,如果消息是以 `/name` 开头,则表示客户端发送了自己的名称,将其保存到 `Client` 结构体中,并向所有客户端广播其加入聊天室的消息。如果消息是以 `/whisp` 开头,则表示客户端想私聊某个用户,将消息发送给指定用户。如果消息是以 `/file` 开头,则表示客户端想发送文件给某个用户,将文件发送给指定用户。其他情况则表示客户端发送了群聊消息,将其向所有客户端广播。 在主函数中,创建服务器套接字并绑定端口号,然后等待客户端连接。每当有客户端连接时,就创建一个新的线程来处理客户端。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝士是只猫

开源使得世界变得更美丽

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值