当前位置:   article > 正文

Winsock使用之创建客户端Socket_winsock sock

winsock sock

创建客户端Socket

初始化以后,SOCKET对象必须由客户端实例化

1.声明一个addrinfo对象,它包含一个sockaddr结构,然后初始化这些值。此应用程序,互联网地址族未指明,所以或者返回IPv6地址或者IPv4地址。应用程序要求socket类型为SOCK_STREAM(提供面向连接的稳定数据传输,即TCP协议)。

  1. struct addrinfo *result = NULL,
  2. *ptr = NULL,
  3. hints;
  4. ZeroMemory( &hints, sizeof(hints) );
  5. hints.ai_family = AF_UNSPEC;
  6. hints.ai_socktype = SOCK_STREAM;
  7. hints.ai_protocol = IPPROTO_TCP;

2.调用getaddrinfo函数为在命令行上输出的服务器请求IP地址。在这个示例中,客户端将要连接的服务器上的TCP端口DEFAULT_PORT 宏定义为 27015。getaddrinfo函数返回一整型,检查错误。

  1. #define DEFAULT_PORT "27015"
  2. // Resolve the server address and port
  3. iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
  4. if (iResult != 0) {
  5. printf("getaddrinfo failed: %d\n", iResult);
  6. WSACleanup();
  7. return 1;
  8. }
3.创建一个SOCKET 对象称为ConnectSocket。

SOCKET ConnectSocket = INVALID_SOCKET;

4.调用socket函数并返回其值给ConnectSocket变量 。 此应用程序,使用由getaddrinfo 返回第一个IP地址来匹配参数hints的地址族、socket类型和指定协议。示例中,TCP流套接字指定socket类型 为SOCK_STREAM ,协议为IPPROTO_TCP。未指定地址族(AF_UNSPEC ),所以会返回IPv6或者IPv4给服务器。
如果客户端程序只想用IPv6或者IPv4,参数hints的地址族需要设置为:IPv6为 AF_INET6 或者IPv4为 AF_INET。
  1. // Attempt to connect to the first address returned by// the call to getaddrinfo
  2. ptr=result;
  3. // Create a SOCKET for connecting to server
  4. ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
  5. ptr->ai_protocol);
5.检查错误,保证 SOCKET 是有效的。
  1. if (ConnectSocket == INVALID_SOCKET) {
  2. printf("Error at socket(): %ld\n", WSAGetLastError());
  3. freeaddrinfo(result);
  4. WSACleanup();
  5. return 1;
  6. }
小结:
(1)传递给socket函数的参数可能会有不同的实现。
(2)错误检测是网络编码的关键部分。如果 socket执行失败,将会返回INVALID_SOCKET。上面代码中的if语句就是被用来捕获在创建socket时可能发生的错误。WSAGetLastError返回与最后错误发生相关联的错误号。
(3)更广泛的错误检查可能是必要的,取决于应用程序。
(4)WSACleanup用于终止使用WS2_32.dll。

连接socket

对于客户端来说,要在网络上通信,必须连接服务器。
调用connect函数,传递socket和sockaddr结构体参数。检查一般错误。
  1. // Connect to server.
  2. iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
  3. if (iResult == SOCKET_ERROR) {
  4. closesocket(ConnectSocket);
  5. ConnectSocket = INVALID_SOCKET;
  6. }
  7. // 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
  8. freeaddrinfo(result);
  9. if (ConnectSocket == INVALID_SOCKET) {
  10. printf("Unable to connect to server!\n");
  11. WSACleanup();
  12. return 1;
  13. }
小结:
(1) getaddrinfo函数用于确定sockaddr结构体的值。本示例中,getaddrinfo 函数返回的第一个 IP 地址用来指明传递到connect 的sockaddr结构体。如果调用首个IP地址失败,然后试着把链接列表中的下一个addrinfo结构体从getaddrinfo 函数返回。
(2) sockaddr结构体中指定的信息包括:
  • 客户端将要连接的服务器IP地址
  • 客户端将要连接的服务器端口号,当客户端调用getaddrinfo 函数时,端口指定为 27015。

客户端发送和接收数据

下面代码示范,连接成功后,客户端中使用的send和recv函数
  1. #define DEFAULT_BUFLEN 512
  2. int recvbuflen = DEFAULT_BUFLEN;
  3. char *sendbuf = "this is a test";
  4. char recvbuf[DEFAULT_BUFLEN];
  5. int iResult;
  6. // Send an initial buffer
  7. iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);
  8. if (iResult == SOCKET_ERROR) {
  9. printf("send failed: %d\n", WSAGetLastError());
  10. closesocket(ConnectSocket);
  11. WSACleanup();
  12. return 1;
  13. }
  14. printf("Bytes Sent: %ld\n", iResult);
  15. // shutdown the connection for sending since no more data will be sent// the client can still use the ConnectSocket for receiving data
  16. iResult = shutdown(ConnectSocket, SD_SEND);
  17. if (iResult == SOCKET_ERROR) {
  18. printf("shutdown failed: %d\n", WSAGetLastError());
  19. closesocket(ConnectSocket);
  20. WSACleanup();
  21. return 1;
  22. }
  23. // Receive data until the server closes the connectiondo {
  24. iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  25. if (iResult > 0)
  26. printf("Bytes received: %d\n", iResult);
  27. else if (iResult == 0)
  28. printf("Connection closed\n");
  29. else
  30. printf("recv failed: %d\n", WSAGetLastError());
  31. } while (iResult > 0);
小结:
send 和recv都会返回一个整性值表示各自发送和接收的整数值,或者错误。每一个函数都采用相同的参数:活动socket、char型buffer、发送或接受字节数量和使用标志。

断开客户端

一旦客户端已完成发送和接收数据,客户端断开连接的服务器和关闭socket。
1.当客户端完成发送数据到服务器时,shutdown函数被调用指定 SD_SEND来关闭socket的发送方。这使得服务器为此socket释放一些资源。客户端应用程序仍然可以接收socket上的数据。
  1. // shutdown the send half of the connection since no more data will be sent
  2. iResult = shutdown(ConnectSocket, SD_SEND);
  3. if (iResult == SOCKET_ERROR) {
  4. printf("shutdown failed: %d\n", WSAGetLastError());
  5. closesocket(ConnectSocket);
  6. WSACleanup();
  7. return 1;
  8. }
2.当客户端应用程序完成接收数据时,closesocket函数被调用来关闭socket。当客户端应用程序完成后使用WS2_32.dll,WSACleanup 函数被调用以释放资源。

  1. // cleanup
  2. closesocket(ConnectSocket);
  3. WSACleanup();
  4. return 0;

编辑于2016年8月3日 By Seefun_Zhu

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/147103
推荐阅读
相关标签
  

闽ICP备14008679号