Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
成功接收后清空缓冲区 我在Windows上编写了一个C++服务器,我面临着一个奇怪的行为:使用代码> ReCVE()/ < /P>_C++_Sockets_Tcp_Winsock_Recv - Fatal编程技术网

成功接收后清空缓冲区 我在Windows上编写了一个C++服务器,我面临着一个奇怪的行为:使用代码> ReCVE()/ < /P>

成功接收后清空缓冲区 我在Windows上编写了一个C++服务器,我面临着一个奇怪的行为:使用代码> ReCVE()/ < /P>,c++,sockets,tcp,winsock,recv,C++,Sockets,Tcp,Winsock,Recv,我写了这个函数: bool readN(SOCKET s, int size, char* buffer){ fd_set readset; struct timeval tv; int left, res; FD_ZERO(&readset); FD_SET(s, &readset); left = size; std::cout << "-----called readN to read " <<

我写了这个函数:

bool readN(SOCKET s, int size, char* buffer){
    fd_set readset;
    struct timeval tv;
    int left, res;
    FD_ZERO(&readset);
    FD_SET(s, &readset);
    left = size;
    std::cout << "-----called readN to read " << size << " byte" << std::endl;
    while (left > 0) {
        tv.tv_sec = MAXWAIT;
        tv.tv_usec = 0;
        res = select(0, &readset, NULL, NULL, &tv);
        if (res > 0) {
            res = recv(s, buffer, left, 0);
            if (res == 0) {//connection closed by client
                return false;
            }

            left -= res;
            std::cout << "\treceived " << res << " left " << left << std::endl;
            if (left != 0) {
                buffer += res;
            }

        }
        else if (res == 0) { //timer expired
            return false;
        }
        else { //socket error
            return false;
        }
    }
    std::cout << "\t" << buffer << std::endl;
    return true;
}
bool readN(套接字、int大小、字符*缓冲区){
fd_集readset;
结构时间值电视;
int左,res;
FD_零(读取集和读取集);
FD_集和读取集;
左=大小;

std::cout在
readN()的末尾有

std::cout << "\t" << buffer << std::endl;
这将输出缓冲区

std::cout << "\t" << (buffer - size) << std::endl;

我发现您的代码中有一些问题

  • 每次调用
    select()
    select()
    时,您不会重置
    readset
    变量。对于单个套接字来说,这并不太糟糕,但您应该养成每次重置变量的习惯

  • 您没有检查由
    recv()
    返回的错误。您假定任何不正常的断开都是成功的,但这并不总是正确的

  • 在返回
    true
    之前的
    readN()
    末尾,您正在将
    buffer
    参数输出到
    std::cout
    ,但是
    buffer
    将指向数据的末尾,而不是开始,因为它是由读取循环推进的。这可能是您对“空缓冲区”的混淆之处来自。
    readN()
    本身甚至不应该输出数据,因为您在退出
    readN()
    后才这样做,否则您将得到冗余的输出消息


  • 如果
    readN()
    返回true,则使用
    运算符将最终的
    缓冲区传递给
    std::cout
    ,或定义“缓冲区仍然为空”。该断言的证据是什么?并且忽略了
    recv()的可能性
    返回了-1。我建议您调试代码。特别是在recv调用时中断,然后检查缓冲区,这比让其他人在心里调试它更合理。我调试了程序,recv返回的值为正值,但缓冲区内容为“\0”,但您仍然是对的,我没有处理-1的情况。您为什么这样做你认为另一端没有给你发送一些
    '\0'
    字节吗?试着在通话前填写(例如)
    '\0x5A'
    ,看看是否有变化。在这种情况下,你会收到大量
    \0
    字节。如果这不是你所期望的,你有一个bug需要修复。
    buffer += res;
    
    std::cout << "\t" << (buffer - size) << std::endl;
    
    #include <iostream>
    #include <memory>
    #include <string.h>
    
    #ifdef _WIN64
    #include <ws2tcpip.h>
    #else
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #endif
    
    #include <errno.h>
    
    #define MAXWAIT 5000
    
    bool readN(SOCKET fd, int size, char *buffer)
    {
        fd_set readset;
        struct timeval tv;
        int left, res;
    
        FD_ZERO(&readset);
        FD_SET(fd, &readset);
    
        left = size;
        std::cout << "-----called readN to read " << size << " byte" << std::endl;
        while (left > 0) {
            tv.tv_sec = MAXWAIT;
            tv.tv_usec = 0;
            res = select(fd + 1, &readset, NULL, NULL, &tv);
    
            if (res > 0) {
                res = recv(fd, buffer, left, 0);
                if (res == 0) { //connection closed by client
                    return false;
                }
    
                left -= res;
                std::cout << "\treceived " << res << " left " << left << std::endl;
                buffer += res;
            } else if (res == 0) {  //timer expired
                std::cout << "\ttimer expired" << std::endl;
                return false;
            } else {        //socket error
                std::cout << "\tsocket error " << WSAGetLastError()  << std::endl;
                return false;
            }
        }
        std::cout << "Print the buffer now\n" << (buffer - size) << std::endl;
        return true;
    }
    
    int main(void)
    {
        int err;
        SOCKET cfd = 0;
        SOCKET afd = 0;
    
        struct sockaddr_in addr;
        socklen_t clen;
        struct sockaddr_in caddr;
    
    #ifdef _WIN64
        WORD ver = 0x202;
        WSADATA wsa_data;
    
        memset(&wsa_data, 0, sizeof(wsa_data));
        std::cout << "WSAStartup" << std::endl;
        err = WSAStartup(ver, &wsa_data);
        if (err < 0) goto error_exit;
    #endif
    
        memset(&addr, 0, sizeof(addr));
        memset(&caddr, 0, sizeof(caddr));
    
        std::cout << "socket" << std::endl;
        afd = socket(AF_INET, SOCK_STREAM, 0);
        if (afd < 0) goto error_exit;
    
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(1234);
    
        std::cout << "bind" << std::endl;
        err = bind(afd, (struct sockaddr *)&addr, sizeof(addr));
        if (err < 0) goto error_exit;
    
        std::cout << "listen" << std::endl;
        listen(afd, 5);
    
        clen = sizeof(caddr);
        std::cout << "accept" << std::endl;
        cfd = accept(afd, (struct sockaddr *) &caddr, &clen);
        if (cfd == INVALID_SOCKET) goto error_exit;
    
        {
            int size_ = 1024;
            std::unique_ptr<char[]> buffer2 = std::make_unique<char[]>(size_);
    
            std::cout << "readN" << std::endl;
            if (readN(cfd, 1024, buffer2.get())) {
                std::cout << "----read message----" << std::endl;
                std::cout <<"\t"<< buffer2.get() << std::endl;
            }
        }
        return 0;
    error_exit:
        std::cout << "Error!" << std::endl;
        std::cout << "\tsocket error " << WSAGetLastError()  << std::endl;
        return 1;
    }
    
    bool readN(SOCKET s, int size, char* buffer){
        fd_set readset;
        struct timeval tv;
        int res;
        std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
        while (size > 0) {
            FD_ZERO(&readset);
            FD_SET(s, &readset);
            tv.tv_sec = MAXWAIT;
            tv.tv_usec = 0;
    
            res = select(0, &readset, NULL, NULL, &tv);
            if (res > 0) {
                res = recv(s, buffer, size, 0);
                if (res == SOCKET_ERROR) {
                    res = WSAGetLastError();
                    if (res == WSAEWOULDBLOCK) {
                        continue; //call select() again
                    }
                    return false; //socket error
                }
    
                if (res == 0) {
                    return false;  //connection closed by client
                }
    
                buffer += res;
                size -= res;
    
                std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
            }
    
            /*
            else if (res == 0) {
                return false; //timer expired
            }
            else {
                return false; //socket error
            }
            */
    
            else {
                return false; //timer expired or socket error
            }
        }
    
        return true;
    }
    
    std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size_);
    if (readN(sck, size_, buffer.get())) {
        std::cout << "----read message----" << std::endl;
        std::cout << "\t";
        std::cout.write(buffer.get(), size_);
        std::cout << std::endl;
    }
    
    sck = socket(...);
    
    DWORD timeout = MAXWAIT * 1000;
    setsockopt(sck, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
    
    bool readN(SOCKET s, int size, char* buffer){
        int res;
        std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
        while (size > 0) {
            res = recv(s, buffer, size, 0);
            if (res == SOCKET_ERROR) {
                /*
                res = WSAGetLastError();
                if (res == WSAETIMEDOUT) {
                    return false; //timer expired
                }
                else {
                    return false; //socket error
                }
                */
                return false; //timer expired or socket error
            }
    
            if (res == 0) {
                return false; //connection closed by client
            }
    
            buffer += res;
            size -= res;
    
            std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
        }
    
        return true;
    }
    
    bool readN(SOCKET s, int size, char* buffer){
        fd_set readset;
        struct timeval tv;
        int res;
        std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
        while (size > 0) {
            res = recv(s, buffer, size, 0);
            if (res == SOCKET_ERROR) {
                res = WSAGetLastError();
                if (res != WSAEWOULDBLOCK) {
                    return false; //socket error
                }
    
                FD_ZERO(&readset);
                FD_SET(s, &readset);
                tv.tv_sec = MAXWAIT;
                tv.tv_usec = 0;
    
                res = select(0, &readset, NULL, NULL, &tv);
                if (res > 0) {
                    continue; //call recv() again
                }
    
                /*
                else if (res == 0) {
                    return false; //timer expired
                }
                else {
                    return false; //socket error
                }
                */
    
                return false; //timer expired or socket error
            }
    
            if (res == 0) {
                return false; //connection closed by client
            }
    
            buffer += res;
            size -= res;
    
            std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
        }
    
        return true;
    }