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\n" << WSAGetLastError() << endl;;
        closesocket(sockSer);
        WSACleanup();
        return -1;
    }
    cout << "Accepted\n" ;

    //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 *).

 

posted @ 2019-04-03 10:26  Single_Dont  阅读(479)  评论(0编辑  收藏  举报