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

来源:互联网 发布:刺客袖剑淘宝 编辑:程序博客网 时间:2024/06/05 15:37

(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 portiResult = 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 getaddrinfoptr=result;// Create a SOCKET for connecting to serverConnectSocket = 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 messagefreeaddrinfo(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 512int recvbuflen = DEFAULT_BUFLEN;char *sendbuf = "this is a test";char recvbuf[DEFAULT_BUFLEN];int iResult;// Send an initial bufferiResult = 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 dataiResult = 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 connectiondo {    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 sentiResult = 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.

    // cleanupclosesocket(ConnectSocket);WSACleanup();return 0;



原创粉丝点击