select函数保持返回-1

时间:2014-07-29 18:10:29

标签: c++ sockets winsock tcplistener winsock2

我试图创建一个接受使用tcp套接字的客户端的简单示例,并使用winsock的select函数处理它们。

问题是,当我运行select函数时,它会一直返回值-1(错误),WSAGetLastError返回值10022。

我无法找出我做错了什么,因为fd_set正确设置套接字并且maximum_sd设置为正确的值。

#include "stdafx.h"
#include <stdio.h>
#include <thread>
#include <queue>
#include <string.h>
#include <WinSock2.h>
#include <iostream>
#include <Windows.h>

using namespace std;

void SlaveThread(queue<char*>* tasks);
void MasterThread(queue<char*>* tasks);

fd_set readfds;
int max_sd = 0;
deque<SOCKET> socketsQueue;
int nSocketsAmount = 0;

int _tmain(int argc, _TCHAR* argv[])
{

    queue<char*>* tasksQueue = new queue<char*>();
    FD_ZERO(&readfds);
    thread SecondThread(MasterThread,tasksQueue);
    thread FirstThread(SlaveThread,tasksQueue);

    int nReady;
    struct timeval timeout={0, 0};
    timeout.tv_sec=10;
    timeout.tv_usec=0;
    while (true)
    {
        int i;

        nReady = select(max_sd + 1, &readfds, NULL, NULL, &timeout);

         for (i=0; i < nSocketsAmount && nReady > 0; i++)
         {
             SOCKET temp = socketsQueue[i];
             if (FD_ISSET(temp, &readfds)) {

                char buffer[200];
                memset(buffer, 0, 200);
                recv(temp, buffer, 200, 0);
                tasksQueue->push(buffer);
                nReady--;
            }
         }
    }

    FirstThread.join();
    SecondThread.join();
    return 0;
};

void SlaveThread(queue<char*>* tasks)
{
    while (true)
    {
        if (!tasks->empty())
        {
            cout << tasks->front() << " Queue size : " << tasks->size() << endl;
            tasks->pop();
        }

        Sleep(1000);
    }
};

void MasterThread(queue<char*>* tasks)
{
    WSAData WinSockData;
    WORD Version = MAKEWORD(2, 1);

    WSAStartup(Version, &WinSockData);

    /* Create socket structure */
    SOCKADDR_IN Server;
    Server.sin_addr.s_addr = inet_addr("10.0.0.7");
    Server.sin_family = AF_INET;
    Server.sin_port = htons(27015);

    SOCKET ListenSock = socket(AF_INET, SOCK_STREAM, NULL);
    SOCKET Connect;
    ::bind(ListenSock, (SOCKADDR*)&Server, sizeof(Server));
    int errno0 = WSAGetLastError();
    listen(ListenSock, 1);
    int errno1 = WSAGetLastError();
    cout << "Listening on port 27015" << endl;
    char buffer[200];
    int size = sizeof(Server);

    while (true)
    {
        if (Connect = accept(ListenSock, (SOCKADDR*)&Server, &size))
        {
            cout << "Connection established..." << endl;
            FD_SET(Connect, &readfds);

            socketsQueue.push_front(Connect);
            nSocketsAmount++;

            if (Connect > max_sd)
            {
                max_sd = Connect;
            }
        }
    }

    WSACleanup();
};

主线程将套接字添加到fd_set和套接字队列。并且主要使用select来获取套接字需要读取的内容。

任何建议为什么会发生这种情况?

谢谢。

2 个答案:

答案 0 :(得分:2)

readfds正在使用select时,谁(哪个文档页面)允许您更改select

当您将数据结构传递给API函数时,该函数将拥有该函数,直到它返回(或者对于重叠I / O的缓冲区更长)。你不能从另一个线程覆盖它。

您需要将主select循环和“主”线程组合在一起,幸运的是{{1}}完全能够等待侦听套接字上的传入连接。

您遇到的实际错误是违反了文档中的此要求:

  

任何两个参数readfds,writefds或exceptfds都可以为null。至少有一个必须是非null,并且任何非null描述符集必须至少包含一个套接字句柄。

在应用我上面描述的重新设计之后,该集将始终包含侦听套接字,同时解决了这个问题。

答案 1 :(得分:0)

10022是WSAEINVAL。您将无效参数传递给select()。您没有考虑的一件事是select()在退出时修改了提供的fd_set结构,因此每次调用select()时都必须重置它们。在fd_set可能仍在使用select()时,您也没有考虑到您正在修改#include "stdafx.h" #include <stdio.h> #include <thread> #include <queue> #include <mutex> #include <string.h> #include <WinSock2.h> #include <iostream> #include <Windows.h> using namespace std; struct taskQueue { queue<char*> items; mutex itemsLock; }; void SlaveThread(taskQueue *tasks); void MasterThread(taskQueue *tasks); deque<SOCKET> socketsQueue; mutex socketsQueueLock; int _tmain(int argc, _TCHAR* argv[]) { WSAData WinSockData; WORD Version = MAKEWORD(2, 1); WSAStartup(Version, &WinSockData); taskQueue tasks; thread SecondThread(MasterThread, &tasks); thread FirstThread(SlaveThread, &tasks); char *buffer = NULL; while (true) { fd_set readfds; FD_ZERO(&readfds); struct timeval timeout = {0}; timeout.tv_sec = 10; timeout.tv_usec = 0; int nReady = 0; { lock_guard<mutex> lock(socketsQueueLock); for (deque<SOCKET>::iterator iter = socketsQueue.begin(); iter != socketsQueue.end(); ++iter) { FD_SET(*iter, &readfds); ++nReady; } } if (nReady == 0) { Sleep(100); continue; } nReady = select(0, &readfds, NULL, NULL, &timeout); if (nReady > 0) { lock_guard<mutex> lock(socketsQueueLock); for (deque<SOCKET>::iterator iter = socketsQueue.begin(); iter != socketsQueue.end(); ++iter) { SOCKET temp = *iter; if (FD_ISSET(temp, &readfds)) { if (!buffer) buffer = new char[201]; memset(buffer, 0, 200); nReady = recv(temp, buffer, 200, 0); if (nReady > 0) { buffer[nReady] = 0; lock_guard<mutex> lock2(tasks.itemsLock); tasks.items.push(buffer); buffer = NULL; } } } } } FirstThread.join(); SecondThread.join(); delete[] buffer; WSACleanup(); return 0; }; void SlaveThread(taskQueue *tasks) { while (true) { { lock_guard<mutex> lock(tasks->itemsLock); if (!tasks->items.empty()) { char *buffer = tasks->items.front(); cout << buffer << " Queue size : " << tasks->items.size() << endl; tasks->items.pop(); delete[] buffer; } } Sleep(1000); } }; void MasterThread(taskQueue *tasks) { /* Create socket structure */ SOCKADDR_IN Server = {0}; Server.sin_addr.s_addr = inet_addr("10.0.0.7"); Server.sin_family = AF_INET; Server.sin_port = htons(27015); SOCKET ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSock == INVALID_SOCKET) { cout << "Cannot create listening socket. Error: " << WSAGetLastError() << endl; return; } if (::bind(ListenSock, (SOCKADDR*)&Server, sizeof(Server)) == SOCKET_ERROR) { cout << "Cannot bind listening socket. Error: " << WSAGetLastError() << endl; closesocket(ListenSock); return; } if (listen(ListenSock, 1) == SOCKET_ERROR) { cout << "Cannot listen on port 27015. Error: " << WSAGetLastError() << endl; closesocket(ListenSock); return; } cout << "Listening on port 27015" << endl; char buffer[200]; int size; SOCKET Connect; while (true) { size = sizeof(Server); Connect = accept(ListenSock, (SOCKADDR*)&Server, &size); if (Connect != INVALID_SOCKET) { cout << "Connection established..." << endl; lock_guard<mutex> lock(socketsQueueLock); socketsQueue.push_front(Connect); } } }; 。并且您不会保护您的任务队列免于并发线程访问。

尝试更像这样的东西:

{{1}}