Winsock(微軟套接字接口)的使用(3)

(3)Building a Socket Client

To create a socket

  1. Declare an addrinfo object that contains a sockaddr structure and initialize these values. For this application, the Internet address family is unspecified so that either an IPv6 or IPv4 address can be returned. The application requests the socket type to be a stream socket for the TCP protocol.
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    
    ZeroMemory( &hints, sizeof(hints) );  //將指定的內存塊清零,而不讓結構的成員數值具有不確定性。
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    //typedef struct addrinfo
    //{
    //    int                 ai_flags;       // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
    //    int                 ai_family;      // PF_xxx
    //    int                 ai_socktype;    // SOCK_xxx
    //    int                 ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
    //    size_t              ai_addrlen;     // Length of ai_addr
    //    char *              ai_canonname;   // Canonical name for nodename
    //    _Field_size_bytes_(ai_addrlen) struct sockaddr *   ai_addr;        // Binary address
    //    struct addrinfo *   ai_next;        // Next structure in linked list
    //}
    
    
  2. Call the getaddrinfo function requesting the IP address for the server name passed on the command line. The TCP port on the server that the client will connect to is defined by DEFAULT_PORT as 27015 in this sample. The getaddrinfo function returns its value as an integer that is checked for errors.(NODE: getaddrinfo函數能夠處理名字到地址以及服務到端口這兩種轉換,返回的是一個addrinfo的結構(列表)指針而不是一個地址清單。這些addrinfo結構隨後可由套接口函數直接使用。)
    int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
    參數說明
    hostname:一個主機名或者地址串(IPv4的點分十進制串或者IPv6的16進制串)
    service:服務名可以是十進制的端口號,也可以是已定義的服務名稱,如ftp、http等
    hints:可以是一個空指針,也可以是一個指向某個addrinfo結構體的指針,調用者在這個結構中填入關於期望返回的信息類型的暗示。舉例來說:如果指定的服務既支持TCP也支持UDP,那麼調用者可以把hints結構中的ai_socktype成員設置成SOCK_DGRAM使得返回的僅僅是適用於數據報套接口的信息。
    result:本函數通過result指針參數返回一個指向addrinfo結構體鏈表的指針。
    返回值:0——成功,非0——出錯
    #define DEFAULT_PORT "27015"
    
    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

  3. Create a SOCKET object called ConnectSocket.
    SOCKET ConnectSocket = INVALID_SOCKET;

  4. Call the socket function and return its value to the ConnectSocket variable. For this application, use the first IP address returned by the call to getaddrinfo that matched the address family, socket type, and protocol specified in the hints parameter. In this example, a TCP stream socket was specified with a socket type of SOCK_STREAM and a protocol of IPPROTO_TCP. The address family was left unspecified (AF_UNSPEC), so the returned IP address could be either an IPv6 or IPv4 address for the server.

    If the client application wants to connect using only IPv6 or IPv4, then the address family needs to be set to AF_INET6 for IPv6 or AF_INET for IPv4 in the hints parameter.

    // Attempt to connect to the first address returned by
    // the call to getaddrinfo
    ptr=result;
    
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
        ptr->ai_protocol);

  5. Check for errors to ensure that the socket is a valid socket.
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

The parameters passed to the socket function can be changed for different implementations.

Error detection is a key part of successful networking code. If the socket call fails, it returns INVALID_SOCKET. The if statement in the previous code is used to catch any errors that may have occurred while creating the socket. WSAGetLastError returns an error number associated with the last error that occurred.

Note  More extensive error checking may be necessary depending on the application.
 WSACleanup is used to terminate the use of the WS2_32 DLL.

For a client to communicate on a network, it must connect to a server.

To connect to a socket

Call the connect function, passing the created socket and the sockaddr structure as parameters. Check for general errors.

// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
    closesocket(ConnectSocket);
    ConnectSocket = INVALID_SOCKET;
}

// Should really try the next address returned by getaddrinfo
// if the connect call failed
// But for this simple example we just free the resources
// returned by getaddrinfo and print an error message

freeaddrinfo(result);

if (ConnectSocket == INVALID_SOCKET) {
    printf("Unable to connect to server!\n");
    WSACleanup();
    return 1;
}

The getaddrinfo function is used to determine the values in the sockaddr structure. In this example, the first IP address returned by the getaddrinfo function is used to specify the sockaddr structure passed to the connect. If the connect call fails to the first IP address, then try the next addrinfo structure in the linked list returned from the getaddrinfo function.

The information specified in the sockaddr structure includes:

  • the IP address of the server that the client will try to connect to.
  • the port number on the server that the client will connect to. This port was specified as port 27015 when the client called the getaddrinfo function.

To send and receive data on the client

The following code demonstrates the send and recv functions used by the client once a connection is established.

Client

#define DEFAULT_BUFLEN 512

int recvbuflen = DEFAULT_BUFLEN;

char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];

int iResult;

// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
    printf("send failed: %d\n", WSAGetLastError());
    closesocket(ConnectSocket);
    WSACleanup();
    return 1;
}

printf("Bytes Sent: %ld\n", iResult);

// shutdown the connection for sending since no more data will be sent
// the client can still use the ConnectSocket for receiving data
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
    printf("shutdown failed: %d\n", WSAGetLastError());
    closesocket(ConnectSocket);
    WSACleanup();
    return 1;
}

// Receive data until the server closes the connection
do {
    iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
    if (iResult > 0)
        printf("Bytes received: %d\n", iResult);
    else if (iResult == 0)
        printf("Connection closed\n");
    else
        printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);

The send and recv functions both return an integer value of the number of bytes sent or received, respectively, or an error. Each function also takes the same parameters: the active socket, a char buffer, the number of bytes to send or receive, and any flags to use.

To disconnect the client

Once the client is completed sending and receiving data, the client disconnects from the server and shutdowns the socket.

Bb530743.wedge(en-us,VS.85).gifTo disconnect and shutdown a socket

  1. When the client is done sending data to the server, the shutdown function can be called specifying SD_SEND to shutdown the sending side of the socket. This allows the server to release some of the resources for this socket. The client application can still receive data on the socket.
    // shutdown the send half of the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

  2. When the client application is done receiving data, the closesocket function is called to close the socket.

    When the client application is completed using the Windows Sockets DLL, the WSACleanup function is called to release resources.

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();
    
    return 0;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章