可以使用socket()函数或者WSASocket()函数来创建套接字。
1 socket()函数与WSASocket()函数的区别
这两个函数的功能都是创建网络通信所需的套接字,并且都是在winsock2.h头文件中定义。主要的区别在于socket()函数是通用的网络编程接口,采用unix系统标准,创建的套接字只能进行同步I/O操作;而WSASocket()函数是Windows专用的网络编程接口,采用Windows系统标注,创建的套接字可以实现同步I/O操作,也可以实现异步I/O操作。
2 socket()函数
2.1 函数格式
该函数的格式为
WINSOCK_API_LINKAGE SOCKET WSAAPI socket(
int af
, int type
, int protocol
);
其中,参数af表示协议的地址族,如果使用IPv4协议,则该参数设置为AF_INET;type指定了套接字的类型,如果创建的套接字使用TCP/IP,则将该参数设置为SOCK_STREAM,如果套接字使用UDP/IP,则该参数设置为SOCK_DGRAM;protocol表示使用的协议,如果使用TCP协议,则该参数设置为IPPROTO_TCP,如果使用UDP协议,则将该参数设置为IPPROTO_UDP。
如果成功创建套接字,则socket()函数的返回值是新创建的套接字的描述符,如果创建套接字失败,则返回值是INVALID_SOCKET。
需要注意的是,socket()函数的三个参数可以设置为相应的整数值,如表1所示。
表1 socket()参数
协议 | af | type(值) | protocol(值) | ||
TCP | AF_INET(2) | SOCK_STREAM | 1 | IPPROTO_TCP | 6 |
UDP | SOCK_DGRAM | 2 | IPPROTO_UDP | 17 |
2.2 相关代码
首先在程序中添加Winsock网络编程的头文件和动态库,接下来对Winsock动态库进行初始化处理。以上步骤详见《Winsock网络编程头文件及库文件的设置》和《Winsock网络编程Winsock动态库初始化》。
以下代码在创建了一个基于TCP/IP协议通信的套接字:
SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET != sock)
{
cout << "创建套接字成功." << endl;
}
else
{
cout << "创建套接字失败." << endl;
}
在“2 socket()函数”中提到,socket()函数的参数也可以用相应的数字表示,所以创建套接字的代码等价于
sock = socket(2, 1, 6);
3 WSASocket()函数
3.1 函数格式
WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(
int af
, int type
, int protocol
, LPWSAPROTOCOL_INFOA lpProtocolInfo
, GROUP g
, DWORD dwFlags
);
该函数的前三个参数与socket()函数相同;lpProtocolInfo是WSAPROTOCOL_INFO结构的指针,该结构中保存了要创建的套接字的特性。如果该参数不是NULL,那么创建的套接字将会绑定到和这个WSAPROTOCOL_INFO结构相关的提供者上;g是已存在的套接字群组的ID或者是创建新套接字时指定的动作,如果g是套接字群组的ID,则将新创建的套接字加入到该套接字群组中,如果g是创建新套接字时指定的动作,则按照指定的动作操作该创建的套接字;dwFlags指定了新创建的套接字的附加属性,例如,如果要求新创建的套接字具有重叠I/O属性,则可以将该参数设置为WSA_FLAG_OVERLAPPED。
如果成功创建了则WSASocket()函数的返回值是新创建的套接字的描述符,如果创建套接字失败,则返回值是INVALID_SOCKET。
3.2 相关代码
以下代码创建了一个基于TCP/IP协议的套接字,该套接字是异步套接字,可实现重叠I/O操作。
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
需要注意的是,使用socket()函数创建的套接字只能是同步套接字;而使用WSASocket()函数创建的套接字可以是同步套接字也可以是异步套接字。