0

所以我在windows中构建了一个多线程套接字库,当我调用recv时我得到了WSA Not Started错误,即使我成功地让一个客户端连接到服务器。我在穿线之前也让它工作,但我不知道从那以后发生了什么。任何帮助,将不胜感激。

Spocket.hpp

    #include <iostream>
    #include <string>
    #include <Windows.h>
    #pragma comment (lib,"ws2_32.lib")

    static bool initialized_ = false;

    class Spocket
    {
    protected:
        WSADATA         wsaData_;
        SOCKET          hSocket_;
        sockaddr_in     service_;
        std::string     addr_;
        USHORT          port_;
        int             exitCode_;

    public:
        Spocket() { 
            initialize(); 
            create_socket(); 
        }
        Spocket(std::string addr, USHORT port)
            : addr_( addr ), port_( port ) { 
                initialize(); 
                create_socket(); 
        }
        Spocket(Spocket spock, SOCKET sock)
            : hSocket_( sock ), 
            wsaData_( spock.wsaData_ ),
            service_( spock.service_ ),
            addr_( spock.addr_ ),
            port_( spock.port_ ) 
        { 
            initialize(); 
        }
        virtual ~Spocket() { close(); }

        void initialize();
        void create_socket();
        void close();

        template<typename T>
        int recv_data(T* i) {
            int ret = recv( hSocket_, reinterpret_cast<char*>(i), 32, 0 );
            if( ret == SOCKET_ERROR )
                cerr << WSAGetLastError() << endl;
            return ret;
        }

        template<typename T>
        int send_data(T* i) {
            int ret = send( hSocket_, reinterpret_cast<char*>(i), sizeof(i), 0 );
            if( ret == SOCKET_ERROR )
                cerr << WSAGetLastError() << endl;
            return ret;
        }
    };

class ServerSpocket : public Spocket
{
public:
    ServerSpocket(std::string addr, USHORT port);
    Spocket* accept_clients();
};


class ClientSpocket : public Spocket
{
public:
    ClientSpocket(std::string addr, USHORT port);
};

Spocket.cpp

#include <iostream>
using namespace std;
#include "../include/spocket.hpp"

void Spocket::initialize() {
    if(!initialized_)
    {
        cout << "Initializing socket..." << endl;

        exitCode_ = EXIT_SUCCESS;
        int iResult = WSAStartup( MAKEWORD(2,2), &wsaData_ );
        if( iResult != NO_ERROR ) {
            cerr << "WSAStartup failed" << endl;
            exitCode_ = EXIT_FAILURE;
            close();
        }
        initialized_ = true;
    }
}

void Spocket::create_socket() {
    hSocket_ = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if( hSocket_ == INVALID_SOCKET )
    {
        cerr << "Error at socket(): " << WSAGetLastError() << endl;
        exitCode_ = EXIT_FAILURE;
        close();
    }

    service_.sin_family = AF_INET;
    service_.sin_addr.s_addr = inet_addr(addr_.c_str());
    service_.sin_port = htons(port_);
}

void Spocket::close() {
    closesocket( hSocket_ );
    WSACleanup();
}

ServerSpocket::ServerSpocket(std::string addr, USHORT port) : Spocket(addr, port) {
    if( bind( hSocket_, (SOCKADDR*)&service_, sizeof(service_) ) == SOCKET_ERROR )
    {
        cerr << "Failed to bind" << endl;
        exitCode_ = EXIT_FAILURE;
        close();
    }

    if( listen( hSocket_, 1 ) == SOCKET_ERROR )
    {
        cerr << "Error listening on socket" << endl;
        exitCode_ = EXIT_FAILURE;
        close();
    }
}

Spocket* ServerSpocket::accept_clients() {
    cout << "Waiting for connection...\n";
    SOCKET hAccepted = INVALID_SOCKET;
    while( hAccepted == INVALID_SOCKET )
        hAccepted = accept( hSocket_, NULL, NULL );
    return new Spocket( *this, hAccepted );
}

ClientSpocket::ClientSpocket(std::string addr, USHORT port) : Spocket(addr, port) {
    if( connect( hSocket_, (SOCKADDR*)&service_, sizeof(service_) ) == SOCKET_ERROR )
    {
        cerr << "Failed to connect" << endl;
        exitCode_ = EXIT_FAILURE;
        close();
    }
}

server_main.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <spocket.hpp>
using namespace std;

vector<HANDLE> hThreads;
vector<DWORD> dwThreadIds;

struct ConnectionInfo
{
    string ip;
    unsigned int port;
    ConnectionInfo( string ip_, unsigned int port_ ) : ip(ip_), port(port_){}
};
static ConnectionInfo ci( "127.0.0.1", 27015 );

DWORD WINAPI clientSession( LPVOID lpParam )
{
    // create new socket to listen for connection attempts
    ConnectionInfo arg = *reinterpret_cast<ConnectionInfo*>(lpParam);
    ServerSpocket listenSock( arg.ip, arg.port );

    // spawn a duplicate thread when a connection is made, and close the current listening socket
    Spocket* sessionSock = listenSock.accept_clients();
    listenSock.close();
    cout << "client connected..." << endl;
    /*
    hThreads.push_back( CreateThread( NULL, 0, clientSession, &ci, 0, NULL ) );
    */

    // service the connected client
    string msg;
    while( sessionSock->recv_data(&msg) != SOCKET_ERROR && msg != "goodbye!" )
    {
        cout << msg << endl;
        msg.clear();
    }

    cout << "finished with client..." << endl;

    // wait quietly for server shutdown
    while( true )
        Sleep( 200 );
    return 0;
}

int main() {
    cout << "[Server]" << endl;
    cout << "starting up..." << endl;

    hThreads.push_back( CreateThread( NULL, 0, clientSession, &ci, 0, NULL ) );

    string input = "";
    do 
        cin >> input;
    while( input != "exit" );

    // close all thread handles here
    cout << "shutting down..." << endl;
    return 0;
}
4

1 回答 1

1

我相信您必须保持“原始”套接字处于活动状态。listenSock.close();sessionSock->recv_data()循环之后移动。

于 2012-04-14T02:14:15.323 回答