سؤال

I am writing a class for TCP/IP Network client communication. In the class header I create a SOCKET member. The class also contains a method for calling WSAStartup and checking the version. The method to make a connection first calls WSAStartup and then initialises the SOCKET member calling the socket() function. See code below. I am wondering if this is "correct", or if there is a better way.

The header file:

/*network.h*/
public class IPnetwork
{
private:
    WSADATA wsaData ;
    SOCKET hSocket ;
    sockaddr_in socketAddress ;
    static const int SERVER_PORT = 502 ;
    unsigned long int = serverIP ;

public:
    IPnetwork(char* serverIPaddress) ;
    bool Connect() ;
    bool Disconnect() ;
    ~IPnetwork() ;

private:
    bool startWinSock() ;
} ;

The source code:

/*network.cpp*/
IPnetwork::IPnetwork(char* serverIPaddress)
{
    serverIP = inet_addr(serverIPaddress) ;
}

bool IPnetwork::Connect()
{
     /* start winsock */
    if(!startWinSock())
    {
        return false ; /* winsock problem */
    }

    /* Create socket */
    if ((hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        return false ; /* could not create socket */
    }

    /* fill socket address structure */
    socketAddress.sin_family = AFINET ;
    socketAddress.sin_port = htons(SERVER_PORT) ;
    socketAddress.sin_addr.S_un.S_addr = serverIP ;

    /* connect */
    if(connect(hSocket,reinterpret_cast<sockaddr*>(&socketAddress), sizeof(sockAddr))!=0)
    {
        return false ; /* could not connect*/
    }

    return true ;

}

bool IPnetwork::startWinSock()
{
    if(WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0),&wsaData)==0)
    {
        /* Check if major version is at least REQ_WINSOCK_VER */
        if (LOBYTE(wsaData.wVersion) < REQ_WINSOCK_VER)
        {
            return false ; /* winsock started but version is too low */
        }
        else
        {
            return true ; /* winsock started with right version*/
        }
    }
    else
    {
        return false ; /* winsock not started */
    }

}
هل كانت مفيدة؟

المحلول

You're worried about defining a variable of type SOCKET, and when its constructor runs?

That's not a problem, since SOCKET is a C-compatible plain-old-data integral type that holds a socket identifier. It isn't an object. There's no non-trivial construction or destruction associated with the variable itself.

نصائح أخرى

WSAStartup() must be called before socket() can be called, otherwise it will return a WSANOTINITIALISED error.

You can call WSAStartup() multiple times. It is preferred to call WSAStartup() only once, but WinSock is reference counted so it can be called multiple times if needed. You must make sure that you call WSACleanup() one time for each time that WSAStartup() succeeds, or else the reference count will be unbalanced. For instance, you could call WSAStartup() in your constructor and call WSACleanup() in your destructor:

public class IPnetwork
{
private:
    WSADATA wsaData ;
    bool wsaInit;
    ...

public:
    IPnetwork(char* serverIPaddress) ;
    ~IPnetwork() ;
} ;

.

IPnetwork::IPnetwork(char* serverIPaddress)
{
    wsaInit = (WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0), &wsaData) == 0);
    ...
}

IPnetwork::~IPnetwork()
{
    if (wsaInit) WSACleanup();
}

bool IPnetwork::Connect()
{
    if (!wsaInit)
        return false ; /* winsock problem */
    ...
}

Though I would typically call them inside of a separate singleton class instead.

While I agree with @Ben that what you're doing is fine, I'd personally try to get this ugliness out of the mainline of your code. IMO, this is one of the rare times it's reasonable to create a global variable, in a header something like this:

#ifndef WS_INITIATOR_INC_
#define WS_INITIATOR_INC_

#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

#include <stdexcept>

struct bad_version : public std::logic_error {
    bad_version(std::string const &s) : logic_error(s) {}
};

struct winsock { 
    static const int version = 2;
    WSADATA wsaData;

    winsock() { 
        WSAStartup(MAKEWORD(2, 2),&wsaData);
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
            throw bad_version("Could not initialize WinSock 2.2");
    }
    ~winsock() { 
        WSACleanup();
    }
} ws_initiator;

#endif

Include this in your main.cpp (or whatever name you give to the file containing main), and it automates initializing/cleaning up sockets (as well as linking with the right library).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top