1. 加载Winsock库:
示例:
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
原型:
int
WSAAPI
WSAStartup(
__in WORD wVersionRequested, //用于指定准备加载的Winsock库的版本,高位字节是次版本,低字节是主版本。通常使用MAKEWORD(x,y)来指定【x是高位字节,y是低位字节】
__out LPWSADATA lpWSAData //用与其加载的库版本有关的信息填充这个结构
);
//WSADATA
typedef struct WSAData {
WORD wVersion; //设置为将要使用的Winsock版本
WORD wHighVersion; //包含了现有的Winsock库的最高版本
#ifdef _WIN64
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
#else
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets; //可以同时打开的最大套接字数量,不固定,尽量不要用这个值
unsigned short iMaxUdpDg; //数据报的最大长度,不固定,尽量不要用这个值
char FAR * lpVendorInfo;
#endif
} WSADATA, FAR * LPWSADATA;
2. 释放:
使用后需要调用WSACleanup函数,来使Winsock释放所有由Winsock分配的资源,并取消这个应用程序挂起的Winsock调用。
原型:
int WSAAPI WSACleanup( void );
出现错误时(比如SOCKET_ERROR),可以调用WSAGetLastError函数来获得一段代码,这段代码专用来说明错误
原型:
#if INCL_WINSOCK_API_PROTOTYPES
WINSOCK_API_LINKAGE
int
WSAAPI
WSAGetLastError(
void
);
#endif /* INCL_WINSOCK_API_PROTOTYPES */
程序通过sockaddr_in结构来指定IP地址和服务端口信息
示例:
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = PF_INET; //#define PF_INET AF_INET,该字段设为AF_INET,以告知Winsock此时正在使用IP地址族。
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(1234); //端口号在选择的时候,需要特别注意,某些端口是“已知的”服务保留的
sockaddr_in结构:
struct sockaddr_in {
short sin_family; //协议族
u_short sin_port; //端口号
struct in_addr sin_addr; //ip
char sin_zero[8]; //填充项,以使SOCKADDR_IN结构和SOCKADDR结构的长度一样
};
inet_addr函数可以将一个点分的IP转换成一个32位的无符号长整数。
网络字节(network-byte)顺序:从最有意义到最无意义的字节排序(big-endian)
将一个数从主机字节顺序转换成网络字节顺序API(具体用法用到的时候再补充吧):
htol
WSAHtol
htons
WSAHtons
SOCKET servSock = socket(AF_INET, SOCK_STREAM, 0);
函数原型:
#if INCL_WINSOCK_API_PROTOTYPES
WINSOCK_API_LINKAGE
__checkReturn
SOCKET
WSAAPI
socket(
__in int af, //协议的地址族
__in int type, //协议的套接字类型。TCP/IP对应SOCK_STREAM;UDP/IP对应SOCK_DGRAM
__in int protocol //用于在给定地址族和套接字类型具有多重入口时,对具体的传送作限定。TCP--IPPROTO_TCP;UDP--IPPROTO_UDP
);
#endif /* INCL_WINSOCK_API_PROTOTYPES */
1. 用Socket或WSASocker将给定的协议的套接字绑定到它已知的名称上
bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
函数原型:
#if INCL_WINSOCK_API_PROTOTYPES
WINSOCK_API_LINKAGE
int
WSAAPI
bind(
__in SOCKET s, //等待客户机连接的套接字
__in_bcount(namelen) const struct sockaddr FAR * name, //缓冲区,根据使用的协议,将实际地址填充到一个地址缓冲区,并在调用bind的时候将其转换为一个struct sockaddr
__in int namelen //要传递的、由协议决定的地址结构的长度
);
#endif /* INCL_WINSOCK_API_PROTOTYPES */
2. 将套接字置为监听模式
listen(servSock, 20);
函数原型:
#if INCL_WINSOCK_API_PROTOTYPES
WINSOCK_API_LINKAGE
int
WSAAPI
listen(
__in SOCKET s, //被绑定的套接字
__in int backlog //指定了被搁置的连接的最大队列长度。
);
#endif /* INCL_WINSOCK_API_PROTOTYPES */
3. 若一台客户机试图创立连接,服务器必须通过accept或WSAAccept调用来接受连接
SOCKADDR clntAddr;
int nSize = sizeof(SOCKADDR);
SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);
函数原型:
#if INCL_WINSOCK_API_PROTOTYPES
WINSOCK_API_LINKAGE
__checkReturn
SOCKET //返回值:一个新的套接字,用于已经被接受的那个客户机的连接。(后续的消息发送什么的应该用这个套接字)
WSAAPI
accept(
__in SOCKET s, //监听的套接字
__out_bcount_opt(*addrlen) struct sockaddr FAR * addr, //新连接的地址信息(输出)
__inout_opt int FAR * addrlen //连接结构体的大小
);
#endif /* INCL_WINSOCK_API_PROTOTYPES */
客户机的创建步骤:
连接:
关闭连接:
一旦应用程序处于ESTABLISHED状态,就可以通过两种方法来关闭它。
主动关闭: