前置只是参考winsocket-cli
创建
WSADATA wsaData;
int iResult;
//initialize Winsock
iResult= WSAStartup(MAKEWORD(2,2),&wsaData);
if(iResult!=0){
std::cout<<"init failed: "<<iResult;
return 1;
}
std::cout<<"start success\n";
std::string defaultPort{"27015"};
struct addrinfo
*result= nullptr,
*ptr= nullptr,
hints;
ZeroMemory(&hints,sizeof (hints));
hints.ai_family=AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult= getaddrinfo(nullptr,defaultPort.c_str(),&hints,&result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET listenSocket=INVALID_SOCKET;
listenSocket= socket(result->ai_family,result->ai_socktype,result->ai_protocol);
if (listenSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
std::cout<<"creat success\n";
特别:AI_PASSIVE 标志指示调用方打算在 调用绑定 函数时使用返回的套接字地址结构。 如果设置了 AI_PASSIVE 标志,并且 getaddrinfo 函数的 nodename 参数为 NULL 指针,则套接字地址结构的 IP 地址部分将设置为 IPv4 地址的 INADDR_ANY,或 iPv6 地址的 IN6ADDR_ANY_INIT。
调用 套接字 函数并将其值返回到 ListenSocket 变量。 对于此服务器应用程序,请使用调用 getaddrinfo 返回的第一个 IP 地址,该地址与 hints 参数中指定的地址系列、套接字类型和协议匹配。 在此示例中,请求了 IPv4 的 TCP 流套接字,地址系列为 IPv4,套接字类型为 SOCK_STREAM,协议为 IPPROTO_TCP。 因此,为 ListenSocket 请求 IPv4 地址。
如果服务器应用程序想要侦听 IPv6,则需要在 hints 参数中将地址系列设置为 AF_INET6。 如果服务器想要同时侦听 IPv6 和 IPv4,则必须创建两个侦听套接字,一个用于 IPv6,另一个用于 IPv4。 应用程序必须单独处理这两个套接字。
绑定
iResult= bind(listenSocket,result->ai_addr,static_cast<int>(result->ai_addrlen));
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(listenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
std::cout<<"bind success\n";
bind:函数将本地地址与套接字相关联
监听
if ( listen( listenSocket, SOMAXCONN ) == SOCKET_ERROR ) {
printf( "Listen failed with error: %ld\n", WSAGetLastError() );
closesocket(listenSocket);
WSACleanup();
return 1;
}
std::cout<<"listen success\n";
调用 listen 函数,将作为参数传递给创建的套接字和 积压工作的值,以及要接受的挂起连接队列的最大长度。 在此示例中, 积压工作 参数设置为 SOMAXCONN。 此值是一个特殊常量,指示此套接字的 Winsock 提供程序允许队列中最大合理的挂起连接数。 检查一般错误的返回值。
接受
SOCKET cliSocket=INVALID_SOCKET;
cliSocket= accept(listenSocket, nullptr, nullptr);
if (cliSocket == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
return 1;
}
std::cout<<"accept success\n";
使用 Winsock 有多种不同的编程技术可用于侦听多个客户端连接。 一种编程技术是创建一个连续循环,该循环使用 侦听 函数检查连接请求 (请参阅 侦听套接字) 。 如果发生连接请求,应用程序将调用 accept、 AcceptEx 或 WSAAccept 函数,并将工作传递给另一个线程来处理请求。 还可以使用其他几种编程技术。请注意,此基本示例非常简单,不使用多个线程。 该示例还只侦听 并仅接受单个连接。
accept:允许在套接字上进行传入连接尝试。
两个null:
[out] addr
指向接收连接实体地址的缓冲区的可选指针,该地址称为通信层。 addr 参数的确切格式由创建 sockaddr 结构中的套接字时建立的地址系列确定。
[in, out] addrlen
指向包含 addr 参数指向的结构长度的整数的可选指针。
收发信息与结束
//no longer need listen socket
closesocket(listenSocket);
int iSendResult=0;
const int receiveBuffLen=512;
char receiveBuff[receiveBuffLen];
do{
std::cout<<"receiveing\n";
iResult= recv(cliSocket,receiveBuff,receiveBuffLen,0);
if (iResult>0){
printf("Bytes received: %d\n",iResult);
std::cout<<"buff is: "<<receiveBuff<<'\n';
// Echo the buffer back to the sender
iSendResult = send( cliSocket, receiveBuff, iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}else if (iResult==0){
printf("Connection closing...\n");
}else{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
} while (iResult>0);
// shutdown the connection since we're done
iResult = shutdown(cliSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(cliSocket);
WSACleanup();
std::cout<<"closed\n";
完整代码:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
int main() {
WSADATA wsaData;
int iResult;
//initialize Winsock
iResult= WSAStartup(MAKEWORD(2,2),&wsaData);
if(iResult!=0){
std::cout<<"init failed: "<<iResult;
return 1;
}
std::cout<<"start success\n";
std::string defaultPort{"27015"};
struct addrinfo
*result= nullptr,
*ptr= nullptr,
hints;
ZeroMemory(&hints,sizeof (hints));
hints.ai_family=AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult= getaddrinfo(nullptr,defaultPort.c_str(),&hints,&result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET listenSocket=INVALID_SOCKET;
listenSocket= socket(result->ai_family,result->ai_socktype,result->ai_protocol);
if (listenSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
std::cout<<"creat success\n";
iResult= bind(listenSocket,result->ai_addr,static_cast<int>(result->ai_addrlen));
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(listenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
std::cout<<"bind success\n";
if ( listen( listenSocket, SOMAXCONN ) == SOCKET_ERROR ) {
printf( "Listen failed with error: %ld\n", WSAGetLastError() );
closesocket(listenSocket);
WSACleanup();
return 1;
}
std::cout<<"listen success\n";
SOCKET cliSocket=INVALID_SOCKET;
cliSocket= accept(listenSocket, nullptr, nullptr);
if (cliSocket == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
return 1;
}
std::cout<<"accept success\n";
//no longer need listen socket
closesocket(listenSocket);
int iSendResult=0;
const int receiveBuffLen=512;
char receiveBuff[receiveBuffLen];
do{
std::cout<<"receiveing\n";
iResult= recv(cliSocket,receiveBuff,receiveBuffLen,0);
if (iResult>0){
printf("Bytes received: %d\n",iResult);
std::cout<<"buff is: "<<receiveBuff<<'\n';
// Echo the buffer back to the sender
iSendResult = send( cliSocket, receiveBuff, iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}else if (iResult==0){
printf("Connection closing...\n");
}else{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
} while (iResult>0);
// shutdown the connection since we're done
iResult = shutdown(cliSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(cliSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(cliSocket);
WSACleanup();
std::cout<<"closed\n";
return 0;
}
评论区