WinSock TCP 长连接(while循环)

Posted zpchcbd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WinSock TCP 长连接(while循环)相关的知识,希望对你有一定的参考价值。

前面的程序,不管服务器端还是客户端,都有一个问题,就是处理完一个请求立即退出了,没有太大的实际意义。能不能像Web服务器那样一直接受客户端的请求呢?能,使用 while 循环即可。

这里唯一需要注意的是,每次 客户端 进行连接完之后,都需要进行socketclose()的操作,原因是 服务端 调用 closesocket() 不仅会关闭服务器端的 socket,还会通知客户端连接已断开,所以客户端也需要直接进行socketclose()的操作

服务端的代码:

#include<winSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //添加动态链接库

using namespace std;

int main(int argc, char * argv[]) {
    const int   BUFSIZE = 1024;
    SOCKET      ListeningSocket; //定义一个套接字变量
    SOCKET      NewConnection; //客户端的请求生成的新的套接字
    SOCKADDR_IN ClientAddr;
    SOCKADDR_IN ServerAddr;
    char        Message[BUFSIZE];
    int         ClientAddrLen;
    ZeroMemory(Message, BUFSIZE);

    if (argc <= 1)
    {
        cout << "USAGE: TcpServer <Listen Port>" << endl;
        return -1;
    }


    int ret; //用来检查初始化成功是否
    WSADATA wsaDATA; // 创建一个WSADATA 用来初始化套接字网络库

    if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaDATA)) != 0) { // 初始化套接字网络库WinSock2.2版本
        cout << "WSAStartup初始化失败 with error " << ret << endl;
        return -1;
    }

    //创建套接字 AF_INET协议 SOCK_STREAM流 TCP协议
    if ((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) {
        cout << "创建套接字失败 with error " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    //绑定套接字
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(atoi(argv[1]));
    ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        cout << "绑定套接字失败 with error " << WSAGetLastError() << endl;
        closesocket(ListeningSocket);
        WSACleanup();
        return -1;
    }

    //监听套接字
    if ((ret = listen(ListeningSocket, 1)) == SOCKET_ERROR) {
        cout << "监听套接字失败 with error " << WSAGetLastError() << endl;
        closesocket(ListeningSocket);
        WSACleanup();
        return -1;
    }
    cout << "正在监听端口" << argv[1] << "中..." << endl;


    //接收客户端数据
    ClientAddrLen = sizeof(SOCKADDR);
    while (true) {
        if ((NewConnection = accept(ListeningSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET) {//创建一个当前客户端和服务端的套接字,accept会阻塞,后面的不能继续执行,直到有新的请求
            cout << "创建NewConnection失败 with error " << WSAGetLastError() << endl;
            closesocket(ListeningSocket);
            WSACleanup();
            return -1;
        }

        int StrLen = recv(NewConnection, Message, sizeof(Message), 0);
        cout << "客户端 > " << Message << endl;

        send(NewConnection, Message, StrLen, 0);
        closesocket(NewConnection);

        ZeroMemory(Message, BUFSIZE);
    }

    //关闭套接字
    closesocket(ListeningSocket);
    WSACleanup();


    return 0;
}

客户端的代码:

#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib") //添加动态链接库
#pragma warning(disable:4996) //忽略旧函数使用缺陷的警告

using namespace std;

int main(int argc, char * argv[]) {
    const int   BUFSIZE = 1024;
    SOCKET      ClientSocket;
    SOCKADDR_IN ServerAddr;
    char        SendBuf[BUFSIZE];  //发送存储的数据缓冲区
    char        BufRecv[BUFSIZE]; //接收收到的数据缓冲区

    ZeroMemory(SendBuf, BUFSIZE);
    ZeroMemory(BufRecv, BUFSIZE);
    strcpy(SendBuf, "Hello, My Name is Client");

    if (argc <= 2)
    {
        cout << "USAGE: TcpServer <Server IP> <Server PORT>" << endl;
        return -1;
    }

    WSADATA     WSAData;
    int         ret;
    if ((ret = WSAStartup(MAKEWORD(2, 2), &WSAData)) != 0) {
        cout << "WSAStartup初始化失败 with error " << ret << endl;
        return -1;
    }


    //cout << "连接建立成功!" << endl;;

    while (true) {
        //创建套接字
        if ((ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) {
            cout << "创建套接字失败 with error " << WSAGetLastError() << endl;
            WSACleanup();
            return -1;
        }

        //连接connet服务端
        ServerAddr.sin_family = AF_INET;
        ServerAddr.sin_addr.s_addr = inet_addr(argv[1]);
        ServerAddr.sin_port = htons(atoi(argv[2]));
        if (connect(ClientSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) {
            cout << "连接服务端失败 with error " << WSAGetLastError() << endl;
            closesocket(ClientSocket);
            WSACleanup();
            return -1;
        }

        cout << "客户端 > ";
        cin >> SendBuf;

        //send发送数据
        if ((ret = send(ClientSocket, SendBuf, strlen(SendBuf), 0)) == SOCKET_ERROR) {
            cout << "send failed with error " << WSAGetLastError() << endl;;
            closesocket(ClientSocket);
            WSACleanup();
            return -1;
        }

        recv(ClientSocket, BufRecv, BUFSIZ, 0);
        cout << "服务端 > " << BufRecv << endl;

        ZeroMemory(SendBuf, BUFSIZE);
        ZeroMemory(BufRecv, BUFSIZE);

        //关闭套接字
        closesocket(ClientSocket);
    }

    WSACleanup();
    return 0;


}

以上是关于WinSock TCP 长连接(while循环)的主要内容,如果未能解决你的问题,请参考以下文章

丢弃用于 TCP 连接的 winsock 内部缓冲区中的排队数据

java Socket 长连接后,如何获取发来的数据

Winsock - 客户端断开连接,关闭套接字循环/最大连接数

Winsock 连接很慢

winsock winsock2 TCP/IP协议 tcpip.sys 网卡驱动 有啥相互关系?

用java建立网络连接TCP