Windows网络编程(一):创建链接
文章目录
一、使用前的准备
必须使用到的头文件是winsock2.h
和winsock.h
两个头文件中选择一个。
需要注意的是,单纯的引入这个头文件是不能完成代码的编译的。因为winsock
需要使用静态链接库WSOCK32.LIB进行静态链接。因此需要采用以下其中之一的方式将静态库进入,否则在编译的时候会出现以下的错误:
NetDemo-12ac36.o : error LNK2019: 无法解析的外部符号 __imp_WSAStartup,该符号在函数 main 中被引用
NetDemo-12ac36.o : error LNK2019: 无法解析的外部符号 __imp_WSACleanup,该符号在函数 main 中被引用
NetDemo-12ac36.o : error LNK2019: 无法解析的外部符号 __imp_WSAGetLastError,该符号在函数 main 中被引用
- 第一种方法是在代码中进行连接:
#pragma comment(lib, "WSOCK32")
- 第二种方法是在编译是进行连接:
clang++ .\NetDemo.cpp -o NetDemo.exe -L F:\uCard\VC6.0green\VC98\Lib\ -lWSOCK32
二、使用中的初始化
包含头文件之后,需要的做的第二件事就是将winsock
进行初始化,初始化的过程主要是使用这个函数加载合适的winsock DLL
。然后才能进行使用,使用的初始化函数原型如下:
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
然后使用winsock
进行socket编程,使用完winsock
之后,最终需要将socket进行释放资源,使用的是以下的函数原型如下:
int WSACleanup();
本函数原型的使用实例是:
WSAData wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
WSACleanup();
三、错误处理
在进行编程的时候需要对在网络中出现的问题进行错误检查和错误处理,在这里使用的函数原型如下所示:
int WSAGetLastError();
这个函数接收的错误必须是在winsock
被加载完成之后,才能进行错误的获取,否则不能获取错误。正是因为这个原因,这个函数调用需要在WSAStartup之后获取错误代码。
四、很重要的一个概念——IP寻址
理解结构体——SOCKADDR_IN,这个结构体主要的是以下结构:
struct sockaddr_in
{
short sin_family; // 协议栈
u_short sin_port; // 端口号
struct in_addr sin_addr; // 自己的IP地址
char sin_zero[8];// 用于填充的字节
};
接下来分别介绍以上结构体中的各字段:
- s i n _ f a m i l y sin\_family sin_family:在IP协议栈中的值为AF_INET
- s i n _ p o r t sin\_port sin_port:设置IP地址的端口号
- s i n _ a d d r sin\_addr sin_addr:IP地址的一个结构体:很重要,以下就是针对这个IP地址进行处理。
主要的问题就是将点分十进制转换成为一个长整型函数,主要的函数原型就是以下的函数:
unsigned long inet_addr(const char FAR * cp);
这样可能存在一个问题,对于不同的主机厂商,他们设定的IP地址在本机中的序列可能有所不同,即我们所说的大端字节序和小端字节序的区别。然而在同一个网络上就需要将以上的IP地址进行统一,在这里我们统一使用大端字节序作为网络上IP的标准。
于是针对这一需求,就存在大量的函数用于解决这个问题,将主机字节序转换成为网络字节序。下列的四个API都能实现以上的需求:
u_long htonl(u_long hostlong);// 返回值就是最终的数据 int WSAHtonl(SOCKET s, u_long hostlong, u_long FAR * lpnetlong);// 返回值放置在lpnetlong中 u_short htons(u_short hostshort); int WSAHtons(SOCKET s, u_short hostshort, u_short FAR * lpnetshort);
实现反方向转化的函数为:
u_long htonl(u_long netlong);// 返回值就是最终的数据 int WSAHtonl(SOCKET s, u_long netlong, u_long FAR * lphostlong);// 返回值放置在lpnetlong中 u_short htons(u_short netshort); int WSAHtons(SOCKET s, u_short netshort, u_short FAR * lphostshort);
敬请期待
五、很重要的socket连接概念
socket在网络编程中是一个很重要的概念,针对socket这个结构体有以下的结构:
SOCKET socket(
int af; // 协议的地址族
int type; // 套接字的类型
int protocol; // 使用的协议
);
其实我们不难知道,socket是传输层的一个概念,因此以上的结构体如果我们采用TCP/IP协议族的话,那么以上结构体中各字段的含义如下:
- a f af af:这个值就设置为和以上相同AF_INET
- t y p e type type:这个值根据TCP和UDP的不同而设置为不同的关键字——对于TCP这个字段的值设置为