Winsock使用之创建客户端Socket

创建客户端Socket

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

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

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;

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

#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.创建一个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。
// 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.检查错误,保证 SOCKET 是有效的。
if (ConnectSocket == INVALID_SOCKET) {
    printf("Error at socket(): %ld\n", WSAGetLastError());
    freeaddrinfo(result);
    WSACleanup();
    return 1;
}
小结:
(1)传递给socket函数的参数可能会有不同的实现。
(2)错误检测是网络编码的关键部分。如果 socket执行失败,将会返回INVALID_SOCKET。上面代码中的if语句就是被用来捕获在创建socket时可能发生的错误。WSAGetLastError返回与最后错误发生相关联的错误号。
(3)更广泛的错误检查可能是必要的,取决于应用程序。
(4)WSACleanup用于终止使用WS2_32.dll。

连接socket

对于客户端来说,要在网络上通信,必须连接服务器。
调用connect函数,传递socket和sockaddr结构体参数。检查一般错误。
// 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;
}
小结:
(1) getaddrinfo函数用于确定sockaddr结构体的值。本示例中,getaddrinfo 函数返回的第一个 IP 地址用来指明传递到connect 的sockaddr结构体。如果调用首个IP地址失败,然后试着把链接列表中的下一个addrinfo结构体从getaddrinfo 函数返回。
(2) sockaddr结构体中指定的信息包括:
  • 客户端将要连接的服务器IP地址
  • 客户端将要连接的服务器端口号,当客户端调用getaddrinfo 函数时,端口指定为 27015。

客户端发送和接收数据

下面代码示范,连接成功后,客户端中使用的send和recv函数
#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 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);
小结:
send 和recv都会返回一个整性值表示各自发送和接收的整数值,或者错误。每一个函数都采用相同的参数:活动socket、char型buffer、发送或接受字节数量和使用标志。

断开客户端

一旦客户端已完成发送和接收数据,客户端断开连接的服务器和关闭socket。
1.当客户端完成发送数据到服务器时,shutdown函数被调用指定 SD_SEND来关闭socket的发送方。这使得服务器为此socket释放一些资源。客户端应用程序仍然可以接收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.当客户端应用程序完成接收数据时,closesocket函数被调用来关闭socket。当客户端应用程序完成后使用WS2_32.dll,WSACleanup 函数被调用以释放资源。

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

return 0;

编辑于2016年8月3日 By Seefun_Zhu

猜你喜欢

转载自blog.csdn.net/zhuxipan1990/article/details/52098054
今日推荐