zoukankan      html  css  js  c++  java
  • socket学习笔记——易犯错误

    今天我将分享socket编程,在这条路上的坑,我还能剩多少了!

    之前再linux系统下进行学习,今天尝试再window下进行编程;

    区别:后者需要在进行socket编程,加载socket链接库。

    server端:

    #include<iostream>
    #include<string>
    #include<stdlib.h> 
    using namespace std;
    
    #include<WinSock2.h>
    #include<Ws2tcpip.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    #define CONNECT_NUM_MAX 10   //最大连接数
    #define MSG_MAX_NUM 256        //接受最大数据数
    #define MY_PORT 18000        //端口
    #define MY_IP 127.0.0.1        //IP
    
    int main()
    {
        //0.加载套接字库
        WSADATA wsaData;
        int ret = 0;
        if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
        {
            cout << "WSAStartup(MAKEWORD(2, 2) execute failed!" << endl;
            return -1;
        }
        if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
        {
            WSACleanup();
            cout << "WSADATA version is not correct" << endl;
            return -1;
        }
        
        //1.创建套接字
        SOCKET sockSer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sockSer == INVALID_SOCKET)
        {
            cout << "sockSer create fail" << endl;
            return -1;
        }
    
        //初始化服务器地址族变量
        sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(18000);
        serAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    
        int serLen = sizeof(SOCKADDR);
    
        //2.bind链接
        ret = bind(sockSer, (sockaddr *)&serAddr, serLen);
        if (ret == SOCKET_ERROR)
        {
            cout << "bind execute fail" << endl;
            closesocket(sockSer);
            WSACleanup();
            return -1;
        }
    
        //3.listen监听
        ret = listen(sockSer, CONNECT_NUM_MAX);
        if (ret == SOCKET_ERROR)
        {
            cout << "listen execute failed" << endl;
            closesocket(sockSer);
            return -1;
        }
        else
        {
            cout << "Server is listening on" << serAddr.sin_addr.s_addr << ":" << serAddr.sin_port << "." << endl;
        }
    
        //4.accept
        sockaddr_in cliAddr;
        int cliLen = sizeof(SOCKADDR);
        SOCKET sockCli = accept(sockSer, (sockaddr *)&cliAddr, &cliLen);
        if (sockCli == INVALID_SOCKET)
        {
            cout << "Accepted failed with error code:%d
    " << WSAGetLastError() << endl;;
            closesocket(sockSer);
            WSACleanup();
            return -1;
        }
        cout << "Accepted
    " ;
    
        //5.recv/send
        char sendMsg[MSG_MAX_NUM];
        char recvMsg[MSG_MAX_NUM];
        while (1)
        {
            ZeroMemory(recvMsg, MSG_MAX_NUM);  //对数组进行初始化
            recv(sockCli, recvMsg, 256,0);
            cout <<"Cli:>"<<recvMsg << endl;
    
            ZeroMemory(sendMsg, MSG_MAX_NUM);
            cout << "Ser:>";
            cin >> sendMsg;
            send(sockCli, sendMsg, strlen(sendMsg)+1, 0);
            
        }
    
        //6.close
        closesocket(sockSer);
        return 0;
    }

    坑1:在服务端,我们需要两个SOCKET对象(sockSer和sockCli),前者用来连接、监听和接受客户端请求;后者则在服务端接受客户端请求后返回的sockCli,作为在收发消息的第一个参数。

    坑2:必须将客户端和服务器的端口好进行统一。

    坑3:sockaddr_in 创建的结构体变量,在配置完成后,connect函数中使用需要进行强转(sockaddr *).

    客户端:

    #include<iostream>
    #include<string>
    #include<stdlib.h>
    using namespace std;
    
    #include<WinSock2.h>
    #include<Ws2tcpip.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    #define MSG_MAX_NUM 256
    #define MY_IP 127.0.0.1
    #define MY_PORT 18000
    
    
    int main()
    {
        //0.加载套接字库
        WSADATA wsaData;
        int ret = 0;
        if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
        {
            cout << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed" << endl;
            return -1;
        }
        if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
        {
            WSACleanup();
            cout << "WSADATA version is not correct" << endl;
            return -1;
        }
        //1.创建套接字
        SOCKET sockCli = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sockCli == INVALID_SOCKET)
        {
            cout << "sockCli create failed" << endl;
        }
        //初始化客户端链接服务器端变量
        sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(MY_PORT);
        serAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        
        int serLen = sizeof(sockaddr);
        //2.connect
        ret = connect(sockCli, (sockaddr *)&serAddr, serLen);
        if (ret != 0)
        {
            cout << "connect failed" << endl;
            closesocket(sockCli);
            WSACleanup();
            cin.get();
            return -1;
        }
        //3.收发消息
        char sendMsg[MSG_MAX_NUM];
        char recvMsg[MSG_MAX_NUM];
        while (1)
        {
            ZeroMemory(sendMsg, MSG_MAX_NUM);
            cout << "Cli:>";
            cin >> sendMsg;
            send(sockCli, sendMsg, strlen(sendMsg) + 1, 0);
    
            ZeroMemory(recvMsg, MSG_MAX_NUM);
            recv(sockCli, recvMsg, 256, 0);
            cout << "Ser:>" << recvMsg << endl;
        }
    
        //4.关闭套接字
        closesocket(sockCli);
        return 0;
    }

    坑1:客户端只要一个SOCKET对象,即针对服务端进行连接,发送数据;

    坑2:sockaddr_in 创建的结构体变量,在配置完成后,connect函数中使用需要进行强转(sockaddr *).

  • 相关阅读:
    C# 文件操作(读取文本/日志文件,读取文件列表,创建HTML,写入日志文件)
    网页布局与优化
    深度复制与浅度复制
    Silver 操作Cookie
    HTTP Method小结
    C# 主动发起请求代码
    震动放声音
    细数Objective-C中的回调机制
    iOS7隐藏状态栏 status Bar
    本地化UIImagePicker中的文字
  • 原文地址:https://www.cnblogs.com/single-dont/p/10647191.html
Copyright © 2011-2022 走看看