Windows Socket 2
A socket handle can optionally be a file handle in Windows Sockets 2.
A socket handle from a Winsock provider can be used with other non-Winsock functions such as ReadFile, WriteFile, ReadFileEx, and WriteFileEx.
library: ws2_32.lib(set in Project->Linker->Input->Additional Dependencies)
header: winsock2.h(contains winsock functions, structures and definitions)
ws2tcpip.h contains new functions and structures used to retrieve ip address.
Iphlpapi.h header file is required if an application is using the IP Helper APIs.
Note: #include line for Iphlpapi.h should after the #include line for winsock2.h. windows.h is internally included in winsock2.h. So it is not necessary to include windows.h
For historical reasons, the Windows.h header defaults to including the Winsock.h header file for Windows Sockets 1.1.
So if you include windows.h file will confilt with the socket 2 defined in winsock2.h. In order to prevent this confliction, using WIN32_LEAN_AND_MEAN macro to stop windows.h define windows socket 1.1.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iostream>
using namespace std;
int main() {
WSADATA wsaData;
int iRet = 0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
cout<<::GetLastError()<<endl;
return 1;
}
cout<<std::hex<<wsaData.wVersion<<endl; // 202
cout<<std::hex<<wsaData.wHighVersion<<endl; // 202
cout<<std::dec<<wsaData.szDescription<<endl; // WinSock 2.0
cout<<wsaData.szSystemStatus<<endl; // Running
cout<<wsaData.iMaxSockets<<endl; // 0
return 0;
}
Both gai_strerror and WSAGetLastError can return the error code for the last operation for invoking the api in windows socket program, the later is thread-safe.
GetAddInfo is a macro for GetAddrInfoW or getaddrinfo by whether UNICODE or _UNICODE is defined. The parameter type for this macro should use TCHAR and ADDRINFOT.
GetAddrInfoW uses wchar_t and addrinfoW as its parameter; getaddrinfo uses char and addrinfo.
Syntax for getaddrinfo:
int WSAAPI getaddrinfo(
__in const char* nodename,
__in const char* servname,
__in const struct addrinfo* hints,
__out struct addrinfo** res
);
servname is for the port number, e.g. “11223”.
hints is the addrinfo structure which limit the result of elements in res parameter.
res is the addrinfo structure list, which contains all elements matches the hints.
Syntax for addrinfo:
typedef struct addrinfo
{
int ai_flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
int ai_family; // AF_INET(IPV4), AF_INET6(IPV6), AF_NETBIOS(NETBIOS), AF_BTM(BLUE TOOTH)…
int ai_socktype; // SOCK_STREAM(TCP), SOCK_DGRAM(UDP), SOCK_RAW(RAW)…
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_bcount(ai_addrlen) struct sockaddr * ai_addr; // Binary address
struct addrinfo * ai_next; // Next structure in linked list
}
ADDRINFOA, *PADDRINFOA;
- A value of AI_PASSIVE for ai_flag indicates the socket returned by bind function as Server end, set node name to be null; Otherwise, the socket returned by connect function for connection-oriented protocol(TCP), or connect, sendto or send functions for a connectionless protocol as client and set nodemane and servname as variable.
- A value of AF_UNSPEC for ai_family indicates the caller will accept any protocol family. Be aware that AF_UNSPEC and PF_UNSPEC are the same. Note that AF_ prefix addresses are identical to PF_ prefix protocol family.
- A value of zero for ai_socktype indicates the caller will accept any socket type.
- A value of zero for ai_protocol indicates the caller will accept any protocol.
- The ai_addrlen member must be set to zero.
- The ai_canonname member must be set to NULL.
- The ai_addr member must be set to NULL.
- The ai_next member must be set to NULL.
For retrieving TCP, set ai_socktype as SOCK_STREAM;
If ai_family and ai_socktype are specified for IPV4 or IPV6, ai_protocol should be set as IPROTO_TCP/IPROTO_UDP;
For more details about addrinfo, refer MSDN.
So it is a good manner to zero the content of addrinfo before using it.
All information returned by the GetAddrInfoW function pointed to by the ppResult parameter is dynamically allocated, call FreeAddrInfo to release the memory.
Syntax for FreeAddrInfo asci version
void freeaddrinfo(Note:This continues to free it until ai_next is null.
__in struct addrinfo* ai
);
struct sockaddr {
ushort sa_family;
char sa_data[14];
};
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
- sa_family is address family, like “AF_XXX”, for internet, using AF_INET. sin_family is the same as sa_family. sin_family must be AF_INET.
- If sa_family is AF_INET, sa_data in sockaddr is equal to sin_addr and sin_zero in sockaddr_in. sin_zero Padding to make structure the same size as SOCKADDR. So sockaddr could be used for other protocol; sockaddr_in just for internet protocal(TCP/UDP).
- both of them in network byte order.
struct sockaddr_in6 {sin6_family in sockaddr_in6 and sockaddr_in6_old must be AF_INET6.
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
struct in6_addr sin6_addr;
u_long sin6_scope_id;
};
typedef struct sockaddr_in6 SOCKADDR_IN6;
typedef struct sockaddr_in6 *PSOCKADDR_IN6;
typedef struct sockaddr_in6 FAR *LPSOCKADDR_IN6;
struct sockaddr_in6_old {
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
struct in6_addr sin6_addr;
};
typedef struct sockaddr_storage {
ADDRESS_FAMILY ss_family;
CHAR __ss_pad1[_SS_PAD1SIZE];
__int64 __ss_align;
CHAR __ss_pad2[_SS_PAD2SIZE];
} SOCKADDR_STORAGE, *PSOCKADDR_STORAGE;
typedef UINT_PTR SOCKET;
SOCKET socket = INVALID_SOCKET;
using the first result matched with hints passed in GetAddrInfo function in this way.
SOCKET WSAAPI socket(
_In_ int af,
_In_ int type,
_In_ int protocol
);
_srvsck = socket(ret->ai_family, ret->ai_socktype, ret->ai_protocol);
_srvsck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int bind(
_In_ SOCKET s,
_In_ const struct sockaddr *name,
_In_ int namelen
);
iRet = bind( _srvsck, ret->ai_addr, (int)ret->ai_addrlen);
sockaddr_in undef;
ZeroMemory(&undef, sizeof(sockaddr_in));
undef.sin_family = AF_INET;
undef.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
undef.sin_port = ::htons(11221);
iRet = bind(_srvsck, (sockaddr*)&undef, sizeof(sockaddr_in));
undef.sin_addr.S_un.S_addr = INADDR_ANY;
iRet = bind(_srvsck, (sockaddr*)&undef, sizeof(sockaddr_in));
sockaddr_in _info;
ZeroMemory(&_info, sizeof(sockaddr_in));
int _len = sizeof(sockaddr_in);
iRet = ::getsockname(_srvsck, (sockaddr*)&_info, &_len);
if (iRet == SOCKET_ERROR)
{
iRet = WSAGetLastError();
wcout<<"Failed to getsockname:. (ErrCode: "<<iRet<<")."<<endl;
}
else
{
cout<<"length of sock address:"<<_len<<endl;
char * _paddr = ::inet_ntoa(_info.sin_addr);
if (_paddr != nullptr)
cout<<_paddr<<endl;
else
cout<<"empty ip address"<<endl;
int _port = _info.sin_port;
_port = ::htons(_info.sin_port);
cout<<"port:"<<_port<<endl;
}
int listen(If set backlog to SOMAXCONN, the underlying service provider responsible for socket s will set the backlog to a maximum reasonable value. If a connection request arrives and the queue is full, the client will receive an error with an indication of WSAECONNREFUSED. If the listen function is called on an already listening socket, it will return success without changing the value for the backlog parameter.
_In_ SOCKET s,
_In_ int backlog
);
accept function
SOCKET cltSck = INVALID_SOCKET;
SOCKADDR_IN cltAddr;
int cltAddrLen = sizeof(SOCKADDR_IN);
cltSck = accept(_srvsck, (SOCKADDR*)&cltAddr, &cltAddrLen);
if (cltSck == INVALID_SOCKET)
{
iRet = ::WSAGetLastError();
wcout<<"Failed to accept: "<<gai_strerror(iRet)<<" (ErrCode: "<<iRet<<")."<<endl;
break;
}
ADDRINFOT *res = nullptr, hints;
ZeroMemory(&hints, sizeof(ADDRINFOT));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
iRet = GetAddrInfo(_straddr.c_str(), _strport.c_str(), &hints, &res);
_cltSck = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
iRet = connect(_cltSck, res->ai_addr, res->ai_addrlen);
recvfrom function
iRet = recvfrom(cltSck, (char*)msg, sizeof(TCHAR)*MAX_PATH, 0, (PSOCKADDR)&senderSck, &senderSckSize);If no error occurs, recvfrom returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned.
APPENDIX
Winsock Kernel Socket Categories
AF_INET and AF_INET6
AF_INET | AF_INET6 | |
Socket Address Structure | SOCKADDR_IN | SOCKADDR_IN6 |
Socket Type | SOCK_STREAM
SOCK_DGRAM SOCK_RAW |
SOCK_STREAM
SOCK_DGRAM SOCK_RAW |
Combinations | Basic Sockets
SOCK_DGRAM + IPPROTO_UDP SOCK_RAW + IPPROTO_XXX SOCK_RAW + IPPROTO_XXX |
Same as AF_INET |
System supported socket catalog
On Windows XP and later, the following command can be used to list the Windows Sockets catalog to determine the service providers installed and the address family, socket type, and protocols that are supported.
netsh winsock show catalog