zoukankan      html  css  js  c++  java
  • C++之socket编程

    环境搭建

    1. 开发环境- Clion
      本地安装了vs2017,可以选择使用vs自带的C++编译器,如下图:

      对于vc++

    1. 引入库文件
      socket依赖winsocket.h、winsocket.lib和winsocket.dll
      在CMakeLists中:
    #添加头文件搜索路径
    link_libraries(ws2_32 wsock32)
    

    全部配置:

    cmake_minimum_required(VERSION 3.16)
    project(demo2)
    
    set(CMAKE_CXX_STANDARD 14)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
    
    #add_executable( )
    #添加头文件搜索路径
    link_libraries(ws2_32 wsock32)
    
    
    # 遍历项目根目录下所有的 .cpp 文件
    #file (GLOB_RECURSE files *.cpp)
    #foreach (file ${files})
    #    string(REGEX REPLACE ".+/(.+)\..*" "\1" exe ${file})
    #    add_executable (${exe} ${file} socketDemo/msg_client.cpp overr/overmain.cpp)
    #    message (    -- src/${exe}.cpp will be compiled to bin/${exe})
    #endforeach ()
    
    add_executable(main main.cpp)
    add_executable(client socketDemo/msg_client.cpp)
    add_executable(server socketDemo/msg_server.cpp)
    
    #链接gcc-g++静态库
    #target_link_libraries(demo2 libgcc.a)
    #target_link_libraries(demo2 libstdc++.a)
    #链接网络库(如需要)
    #target_link_libraries(demo2 ws2_32)
    #链接线程库(必须放到最后)
    #target_link_libraries(demo2 libpthread.a)
    

    获取网络中计算机的IP地址和计算机名

    流式套接字编程

      网络数据的传输是靠套接字实现的。套接字有三种类型:流式套接字(socket_stream)、数据包套接字(socket_dgram)和原始套接字(RAW)。

      流式套接字是面向连接的,提供双向、有序、无重复且记录无边界的数据流服务。适用于处理大数据量,开销大

    服务器端编程步骤

    1. 初始化阶段调用函数WSAStartup
        初始化Windows Sockets DLL,只有初始化成功后,才能调用其他Windows API函数。
    void WSAStartup(
        _In_ WORD wVersionRequested,  // 所使用的win socket版本
        _Out_ LPWSADATA lpWSAData //储存系统返回的winSocket信息
        );
    
    1. 建立socket
        初始化动态链接后,在服务端建立一个监听socket
    socket(
        _In_ int af,  // 目前提供PF_INET(AF_INET)
        _In_ int type,  // socket type, e.g. socket_stream(TCP),socket_dgram(UDP)
        _In_ int protocol  // 通讯协议,默认值0
        );
    

    所有的WSASocket函数都可以通过调用 WSAGetLastError()获取上次错误

    1. 绑定端口
    bind(
        _In_ SOCKET s,
        _In_reads_bytes_(namelen) const struct sockaddr FAR * name,  // socket地址,IP
        _In_ int namelen  // name的长度
        );
    

    服务器端程序:

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ws2tcpip.h>
    
    using namespace std;
    
    #define BUF_SIZE 1024
    
    void initialization();
    
    int main()
    {
        //定义长度变量
        int send_len = 0;
        int recv_len = 0;
        int len = 0;
        //定义发送缓冲区和接受缓冲区
        char send_buf[100];
        char recv_buf[100];
        //定义服务端套接字,接受请求套接字
        SOCKET s_server;
        SOCKET s_accept;
        //服务端地址客户端地址
        SOCKADDR_IN server_addr;
        SOCKADDR_IN accept_addr;
        initialization();
        //填充服务端信息
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(5010);
        //创建套接字
        s_server = socket(AF_INET, SOCK_STREAM, 0);
        if (bind(s_server, (SOCKADDR *) &server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
        {
            cout << "套接字绑定失败!" << endl;
            WSACleanup();
        } else
        {
            cout << "套接字绑定成功!" << endl;
        }
        //设置套接字为监听状态
        if (listen(s_server, SOMAXCONN) < 0)
        {
            cout << "设置监听状态失败!" << endl;
            WSACleanup();
        } else
        {
            cout << "设置监听状态成功!" << endl;
        }
        cout << "服务端正在监听连接,请稍候...." << endl;
        //接受连接请求
        len = sizeof(SOCKADDR);
        s_accept = accept(s_server, (SOCKADDR *) &accept_addr, &len);
        if (s_accept == SOCKET_ERROR)
        {
            cout << "连接失败!" << endl;
            WSACleanup();
            return 0;
        }
        cout << "连接建立,准备接受数据" << endl;
        //接收数据
        while (1)
        {
            recv_len = recv(s_accept, recv_buf, 100, 0);
            if (recv_len < 0)
            {
                cout << "接受失败!" << endl;
                break;
            } else
            {
                cout << "客户端信息:" << recv_buf << endl;
            }
    //        cout << "请输入回复信息:";
    //        cin >> send_buf;
            send_len = send(s_accept, "ok..", 100, 0);
            if (send_len < 0)
            {
                cout << "发送失败!" << endl;
                break;
            }
        }
        //关闭套接字
        closesocket(s_server);
        closesocket(s_accept);
        //释放DLL资源
        WSACleanup();
        return 0;
    }
    
    void initialization()
    {
        //初始化套接字库
        WORD w_req = MAKEWORD(2, 2);//版本号
        WSADATA wsadata;
        int err;
        err = WSAStartup(w_req, &wsadata);
        if (err != 0)
        {
            cout << "初始化套接字库失败!" << endl;
        } else
        {
            cout << "初始化套接字库成功!" << endl;
        }
        //检测版本号
        if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
        {
            cout << "套接字库版本号不符!" << endl;
            WSACleanup();
        } else
        {
            cout << "套接字库版本正确!" << endl;
        }
        //填充服务端地址信息
    
    }
    

    客户端程序:

    #include <iostream>
    #include <string>
    #include <WinSock2.h>
    
    using namespace std;
    
    void initialization2();
    void client();
    int main()
    {
        client();
        system("pause");
        return 0;
    }
    
    void client()
    {
        //定义长度变量
        int send_len = 0;
        int recv_len = 0;
        //定义发送缓冲区和接受缓冲区
        char send_buf[100];
        char recv_buf[100];
        //定义服务端套接字,接受请求套接字
        SOCKET s_server;
        //服务端地址客户端地址
        SOCKADDR_IN server_addr;
        initialization2();
        //填充服务端信息
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        server_addr.sin_port = htons(5010);
        //创建套接字
        s_server = socket(AF_INET, SOCK_STREAM, 0);
        if (connect(s_server, (SOCKADDR *) &server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
        {
            cout << "服务器连接失败!" << endl;
            WSACleanup();
        } else
        {
            cout << "服务器连接成功!" << endl;
        }
    
        //发送,接收数据
        while (1)
        {
            cout << "请输入发送信息:";
            cin >> send_buf;
            send_len = send(s_server, "give me", 100, 0);
            if (send_len < 0)
            {
                cout << "发送失败!" << endl;
                break;
            }
            recv_len = recv(s_server, recv_buf, 100, 0);
            if (recv_len < 0)
            {
                cout << "receive err" << endl;
                break;
            }
            else
            {
                cout << "服务端信息:" << recv_buf << endl;
            }
    
        }
        //关闭套接字
        closesocket(s_server);
        //释放DLL资源
        WSACleanup();
    }
    
    void initialization2()
    {
        //初始化套接字库
        WORD w_req = MAKEWORD(2, 2);//版本号
        WSADATA wsadata;
        int err;
        err = WSAStartup(w_req, &wsadata);
        if (err != 0)
        {
            cout << "初始化套接字库失败!" << endl;
        } else
        {
            cout << "初始化套接字库成功!" << endl;
        }
        //检测版本号
        if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
        {
            cout << "套接字库版本号不符!" << endl;
            WSACleanup();
        } else
        {
            cout << "套接字库版本正确" << endl;
        }
        //填充服务端地址信息
    
    }
    

    静态编译

    为了让程序能够顺利移植到其他平台,需要静态链接
    参考
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") :必须

    cmake_minimum_required(VERSION 3.16)
    project(demo3)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
    
    
    add_executable(demo3 main.cpp)
    
    #链接静态库
    #链接boost静态库(project_Name为你的项目名,*分别代表库名、mingw版本号、boost库版本号,如:libboost_system-mgw72-mt-s-1_65_1.a)
    #target_link_libraries(demo3 libboost_*-mgw*-mt-s-*.a)
    #链接gcc-g++静态库
    target_link_libraries(demo3 libgcc.a)
    target_link_libraries(demo3 libstdc++.a)
    #链接网络库(如需要)
    target_link_libraries(demo3 ws2_32)
    #链接线程库(必须放到最后)
    target_link_libraries(demo3 libpthread.a)
    
  • 相关阅读:
    暴力字符串hash——cf1200E
    单调栈+线段树——cf1220F
    拆边+BFS队列骚操作——cf1209F
    控制器
    linux下安装配置jmeter
    docker-compose.yml配置jforum开源系统
    anyproxy
    docker搭建一键安装包lnmp
    docker tomcat,mysql 搭建开源项目jforum
    接口自动化测试-Mock Get和Post请求
  • 原文地址:https://www.cnblogs.com/zhuxiang1633/p/13341727.html
Copyright © 2011-2022 走看看