C++:实现socket通信(TCP/IP)实例(转)

首先声明,博主之前从来没有写过通信方面的东西,这次之所以写这个是因为项目需要,因此本文主要介绍一个使用C++语言及Socket来实现TCP/IP通信的实例,希望可以帮助入门者。

一、什么是TCP/IP?

        TCP提供基于IP环境下的数据可靠性传输,事先需要进行三次握手来确保数据传输的可靠性。详细的博主不再赘述,感兴趣的朋友可以去search一下。

二、什么是socket?    

        socket顾名思义就是套接字的意思,用于描述地址和端口,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

        socket编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW),前两者较常用。基于TCP的socket编程是流式套接字。

三、client/server即C/S模式:

       TCP/IP通信中,主要是进行C/S交互。废话不多说,下面看看具体交互内容:

       服务端:建立socket,申明自身的port和IP,并绑定到socket,使用listen监听,然后不断用accept去查看是否有连接。如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket。如果不需要等待任何客户端连接,那么用closeSocket直接关闭自身的socket。

        客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。

四、编程步骤

1、server端

(1)加载套接字库,创建套接字(WSAStartup()/socket());

    #include<winsock.h>
    #pragma comment(lib,"ws2_32.lib")
     
    void initialization();
     
    int main()
    {
      //创建套接字
      s_server = socket(AF_INET, SOCK_STREAM, 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;
        }
        //填充服务端地址信息
    }

 (2)绑定套接字到一个IP地址和一个端口上(bind());

    server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(5010);

   (3)将套接字设置为监听模式等待连接请求(listen());

    //设置套接字为监听状态
    if (listen(s_server, SOMAXCONN) < 0)
    {
        cout << "设置监听状态失败!" << endl;
        WSACleanup();
    }
    else
    {
        cout << "设置监听状态成功!" << endl;
    }
    cout << "服务端正在监听连接,请稍候...." << endl;

   (4)请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

    //接受连接请求
    len = sizeof(SOCKADDR);
    s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
    if (s_accept == SOCKET_ERROR)
    {
      cout << "连接失败!" << endl;
      WSACleanup();
      return 0;
    }
      cout << "连接建立,准备接受数据" << endl;

    (5)用返回的套接字和客户端进行通信(send()/recv());

    //接收数据
    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, send_buf, 100, 0);
        if (send_len < 0)
            {
          cout << "发送失败!" << endl;
          break;
        }
    }

    (6)返回,等待另一个连接请求;

  (7)关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

    //关闭套接字
    closesocket(s_server);
    closesocket(s_accept);
    //释放DLL资源
    WSACleanup();
    return 0;

     2、Client端

    (1)加载套接字库,创建套接字(WSAStartup()/socket);

    #include<winsock.h>
    #pragma comment(lib,"ws2_32.lib")
     
    void initialization();
     
    int main()
    {
    //创建套接字
    s_server = socket(AF_INET, SOCK_STREAM, 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;
        }
        //填充服务端地址信息
     
    }

   (2)向服务器发出连接请求(connect());

    if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
            cout << "服务器连接失败!" << endl;
            WSACleanup();
        }
        else {
            cout << "服务器连接成功!" << endl;
        }

  (3)和服务器进行通信(send()/recv());

    //发送,接收数据
        while (1) {
            cout << "请输入发送信息:";
            cin >> send_buf;
            send_len = send(s_server, send_buf, 100, 0);
            if (send_len < 0) {
                cout << "发送失败!" << endl;
                break;
            }
            recv_len = recv(s_server, recv_buf, 100, 0);
            if (recv_len < 0) {
                cout << "接受失败!" << endl;
                break;
            }
            else {
                cout << "服务端信息:" << recv_buf << endl;
            }
     
        }

   (4)关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())

    //关闭套接字
        closesocket(s_server);
        //释放DLL资源
        WSACleanup();

五、Windows下基于VS2017实现的socket简单实例(TCP/IP)

(1)server端代码

    #include "pch.h"
    #include<iostream>
    #include<winsock.h>
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    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, send_buf, 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;
        }
        //填充服务端地址信息
     
    }

(2)client端:

    #include "pch.h"
    #include<iostream>
    #include<winsock.h>
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    void initialization();
    int main() {
        //定义长度变量
        int send_len = 0;
        int recv_len = 0;
        //定义发送缓冲区和接受缓冲区
        char send_buf[100];
        char recv_buf[100];
        //定义服务端套接字,接受请求套接字
        SOCKET s_server;
        //服务端地址客户端地址
        SOCKADDR_IN server_addr;
        initialization();
        //填充服务端信息
        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(1234);
        //创建套接字
        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, send_buf, 100, 0);
            if (send_len < 0) {
                cout << "发送失败!" << endl;
                break;
            }
            recv_len = recv(s_server, recv_buf, 100, 0);
            if (recv_len < 0) {
                cout << "接受失败!" << endl;
                break;
            }
            else {
                cout << "服务端信息:" << recv_buf << endl;
            }
     
        }
        //关闭套接字
        closesocket(s_server);
        //释放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;
        }
        //填充服务端地址信息
     
    }

注:对于入门级别学习的同学一些使用指导,想要让这俩程序跑起来,如果只有一台电脑,那么只需要在一台电脑上VS中创建两个不同的控制台应用程序,然后把server和client代码分别copy到这俩新建项目的主程序中,直接运行即可。

六、运行结果显示

(1)server端

(2)client端


————————————————
版权声明:本文为CSDN博主「Cche1」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27923041/article/details/83857964

posted on 2019-08-31 13:33  混元真人  阅读(1347)  评论(0编辑  收藏  举报