Windows Socket API函数的用法及理解(代码实例)
#include "winsock2.h" #pragma comment(lib, "ws2_32.lib") #include "stdlib.h" int main() { WSADATA wsadata; if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) { printf("WSAStartup() 初始化失败!\n"); return -1; } //socket()函数创建与指定的服务提供者绑定套接字 //参数 af:指定协议的地址家族,通常使用AF_INET //参数 type:指定的套接字类型,SOCK_STREAM, SOCK_DGRAM, SOCK_RAW //参数 protocal:套接字使用的协议 //socket() 函数执行成功,返回新Socket的句柄,调用失败返回INVALID_SOCKET //调用socket() 函数创建Socket后,该Socket就存在一个命名空间中,但并没有为其指定一个名称 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { printf("socket() 出错!\n"); } // struct sockaddr_in addr; //指定绑定的地址 int addr_len = sizeof(struct sockaddr_in); //地址的长度 int port = 9901; int errCode; //u_long htonl(u_long hostlong) //该函数将u_long类型的主机字节顺序格式IP地址转换为TCP/IP网络字节顺序格式 //u_short htons(u_short hostshort) //该函数将u_short类型的主机字节顺序格式IP地址转换为TCP/IP网络字节顺序格式 addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind() 函数可以将本地地址与一个Socket绑定在一起,执行成功返回0,调用失败返回SOCKET_ERROR //调用bind() 函数可以为未命名的的Socket 指定一个名称 //名称由地址家族,主机地址,端口号3部分组成(当使用Internet地址家族) //下面的例子使用bind() 函数绑定TCP Socket 到本地地址的9901端口 errCode = bind(s, (SOCKADDR*)&addr, addr_len); if (errCode == SOCKET_ERROR) { printf("bind() 出错\n"); exit(1); } //listen()函数可以将套接字设置为监听接入的状态 //参数 s:指定一个已经绑定但是尚未连接的套接字 //参数 backlog:指定等待连接队列的最大长度 //listen()函数执行成功返回0,调用失败返回SOCKET_ERROR errCode = listen(s, 3); if (errCode == SOCKET_ERROR) { printf("listen() 出错!\n"); exit(1); } SOCKET sockAccept; //执行accept() 函数后新建的用于实际通信的套接字 struct sockaddr_in from; //用于接受接入地址 int len = sizeof(struct sockaddr_in); //使用accept() 函数在处于监听状态的套接字上接受接入请求 //参数 s:通过调用listen() 函数设置为监听状态的套接字 //参数 addr:输出参数,用于接受接入地址信息,这是一个可选参数,如果不关注地址,可以使用NULL //参数 addrlen:输出参数,指定接入地址的长度,这是一个可选参数 //accept() 函数调用成功,返回一个新建的Socket句柄,该Socket用于实现服务器和客户端之间的通信, //如果函数调用失败,则返回INVALID_SOCKET sockAccept = accept(s, (struct sockaddr *)&sockAccept, &len); if (sockAccept == INVALID_SOCKET) { printf("accept() 出错!\n"); } else { //char FAR * inet_ntoa(struct in_addr in) //该函数将in_addr结构体中的IP地址转换为点分法IP地址字符串 //参数 in:是in_addr结构体类型,表示要进行转换的IP地址,返回结果是char *类型的IP地址 printf("%s\n", inet_ntoa(from.sin_addr)); //打印接入地址 } if (WSACleanup() == SOCKET_ERROR) { printf("WSACleanup() 出错!\n\n"); } system("pause"); return 0; } /* #if !defined(MAKEWORD) #define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) #endif #define SOCK_STREAM 1 // stream socket #define SOCK_DGRAM 2 // datagram socket #define SOCK_RAW 3 // raw-protocol interface #define SOCK_RDM 4 //reliably-delivered message #define SOCK_SEQPACKET 5 //sequenced packet stream #define AF_INET 2 // internetwork: UDP, TCP, etc. #define INVALID_SOCKET (SOCKET)(~0) #define SOCKET_ERROR (-1) // IPv4 Socket address, Internet style // typedef struct sockaddr_in { #if(_WIN32_WINNT < 0x0600) short sin_family; #else //(_WIN32_WINNT < 0x0600) ADDRESS_FAMILY sin_family; #endif //(_WIN32_WINNT < 0x0600) USHORT sin_port; IN_ADDR sin_addr; CHAR sin_zero[8]; } SOCKADDR_IN, *PSOCKADDR_IN; // Structure used to store most addresses. // typedef struct sockaddr { #if (_WIN32_WINNT < 0x0600) u_short sa_family; #else ADDRESS_FAMILY sa_family; // Address family. #endif //(_WIN32_WINNT < 0x0600) CHAR sa_data[14]; // Up to 14 bytes of direct address. } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR; #ifndef s_addr #pragma once // // IPv4 Internet address // This is an 'on-wire' format structure. // typedef struct in_addr { union { struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { USHORT s_w1,s_w2; } S_un_w; ULONG S_addr; } S_un; #define s_addr S_un.S_addr //can be used for most tcp & ip code #define s_host S_un.S_un_b.s_b2 // host on imp #define s_net S_un.S_un_b.s_b1 // network #define s_imp S_un.S_un_w.s_w2 // imp #define s_impno S_un.S_un_b.s_b4 // imp # #define s_lh S_un.S_un_b.s_b3 // logical host } IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR; #endif */