源自:http://blog.sina.com.cn/s/blog_a459dcf5010155nf.html
本文针对SOCKET编程中要用到的函数进行一个比较系统的介绍。
说明:在使用Socket时,需要在lib库中使用ws2_32.lib;
1、WSAStartup:初始化套接字环境,本函数必须是应用程序或DLL调用的第一个Windows Sockets函数.它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节.应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数.
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
下面给出WSAStartup函数在实际开发过程中的用法:
//begin 初始化网络环境
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
if ( err != 0)
{
printf("WSAStartup failed with error: %d\n", err);
return -1;
}//end
2、WSACleanup:清理套接字环境,和上面的WSAStartup相反,该函数是在程序不在对任何Windows Sockets函数调用后,用其来清理套接字环境的
int WSACleanup (void);
3、SOCKET socket(int af, int type, int protocol);
建立套接字
参数af用于指定网络地址类型,一般取AF_INET,表示该套接字在Internet域中,进行通信。
参数type用于知道套接字的类型,若取SOCK_STREAM表示创建的套接字是流套接字,而取SOCK_DGRAM创建数字报套接字。
参数protocol用于指定网络协议,一般取0,表示默认为TCP/IP协议。
若套接字创建成功则该函数返回创建的套接字句柄SOCKET,否则产生INVALID_SOCKET错误。
下面给出WSACleanup、socket函数在实际开发过程中的用法:
//begin socket 一个套接字
hTcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == hTcpSocket)
{
MJS_LOG_ERROR("socket failed with error: \n");
WSACleanup();
return -1 ;
}//end
4、int listen(SOCKET s, int backlog);
将套接字置入监听模式并准备接受连接请求。其中,参数s是服务器端套接字,于指定正在等待连接的最大队列长度。如无错误发生,listen函数返回0,失败则返回SOCKET_ERROR错误。
5、SOCKET accept( SOCKET s, struct sockaddr* addr, int* addrlen );
参数s同上,addr是一个有效的SOCKADDR_IN结构的地址,而addrlen是sockaddr_in结果的长度。accept函数返回后,addr参数变量中会包含发出连接请求的那个客户机的IP地址信息,而addrlen参数则指出该结构的长度,并返回一个新的套接字描述符,它对应于已经接受的那个客户机连接。
6、 int bind( SOCKET s, const struct sockaddr* name, int namlen );绑定到本地,name中指定的IP应该是当前运行该程序机器的IP。
7、int connect( SOCKET s, const struct sockaddr FAR* name, int namelen );连接到服务器
下面给出connect函数在实际开发过程中的用法:
int ServePort=20000;
char ServeIP[32]="192.168.1.200";
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(ServePort);
addr.sin_addr.S_un.S_addr = inet_addr(ServeIP);
//连接服务器
if (connect(hTcpSocket, (sockaddr*)&addr, sizeof(sockaddr)) == -1)
{
closesocket(hTcpSocket);
printf("connect Tradesys failed with error%d,%s,%d: \n",ServePort,ServeIP,GetLastError());
WSACleanup();
return -1;
}
else
{
printf("connect Tradesys sucessed,%d,%s: \n",ServePort,ServeIP);
}
8、 int send( SOCKET s, const char* buf, int len, int flags );
s是已建立连接的套接字描述字,参数buf是字符缓冲区,包含即将发送的数据,参数len用于指定即将发送的缓冲区内的字符数。flags可取的值有:0、MSG_DONTROUTE或MSG_OOB或这些标志的按位或运算。
9、int recv( SOCKET s, char* buf, int len, int flags );
s是准备接收数据的套接字,buf是即将收到数据的字符缓冲区,而len则是准备接受的字节数或buf缓冲的长度。flags参数可以是0、MSG_PEEK或MSG_OOB或这些标志的按位“或”运算。
10、int shutdown( SOCKET s, int how );
其中,how参数用于描述禁止哪些操作,它可取的值有:SD_RECEIVE、SD_SEND或SD_BOTH。
如果是SD_RECEIVE,就表示不允许再调用接收函数,
如果选择SD_SEND,表示不允许再调用发送函数,
如果是SD_BOTH, 则表示取消连接两端的收发操作。
如果没有错误发生,shutdown()返回0,否则返回SOCKET_ERROR错误。
11、 int closesocket(SOCKET s );s是要关闭的套接字描述字,再利用套接字执行调用就会失败。
12 int gethostname(char *name, size_t len):这个函数,调用后,会将主机名保存在name里面。而len是name的大小。该函数返回0表示成功,否则失败。
13、struct hostent *gethostbyname(const char *name);
hostent结构:
struct hostent {
char *h_name;//*h_name 表示的是主机的规范名
char **h_aliases;//h_aliases 表示的是主机的别名
int h_addrtype;//地址类型AF_INET,还是AF_INET6
int h_length;//IP地址占字节数
char **h_addr_list;//IP地址列表
};
char *h_name 表示的是主机的规范名。
char **h_aliases 表示的是主机的别名。
int h_addrtype 表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是ipv6(AF_INET6)
int h_length 表示的是主机ip地址的长度
int **h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。
14、const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) ;
这个函数,是将类型为af的网络地址结构src,转换成主机序的字符串形式,存放在长度为cnt的字符串中。这个函数,其实就是返回指向dst的一个指针。如果函数调用错误,返回值是NULL。
15、struct hostent FAR *PASCAL FAR gethostbyaddr(const char FAR * addr, int len, int type);
参数addr:指向网络字节顺序地址的指针。
参数len: 地址的长度,在PF_INET类型地址中为4。
参数type:指地址类型AF_INET、IF_INET6
16、inet_ntoa( char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
将网络地址转换成“.”点隔的字符串格式。本函数将一个用in参数所表示的Internet地址结构转换成以“.” 间隔的诸如“a.b.c.d”的字符串形式。请注意inet_ntoa()返回的字符串存放在WINDOWS套接口实现所分配的内存中。应用程序不应假设该内存是如何分配的。在同一个线程的下一个WINDOWS套接口调用前,数据将保证是有效。
参数in:一个表示Internet主机地址的结构。
返回值:若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NVLL。其中的数据应在下一个WINDOWS套接口调用前复制出来。
上面这几个函数对于完成简单的连接操作是可以胜任的,但是在真正的使用过程中,将会用到更多的函数。
17、unsigned long inet_addr( const char FAR *cp); 将点格式的IP地址转换为无符号类型存储。
18、u_short PASCAL FAR htons( u_short hostshort); 作用是将主机的无符号短整形数转换成网络字节顺序。
19、 u_short PASCAL FAR ntohs( u_short netshort);
20、u_long PASCAL FAR htonl( u_long hostlong);
本函数将一个32位数从主机字节顺序转换成网络字节顺序。
//将主机的unsigned long值转化为网络字节顺序(32位),使用函数htonl()
//参数hostlong标识主机字节顺序的数字,函数返回一个网络字节顺序的数字
#include <winsock.h>
#include <stdio.h>
#pragma comment (lib,"ws2_32.lib")
void main()
{
u_long a = 0x12345678;
u_long b = htonl(a);
printf("%u/n",a);
printf("%x/n",a);
printf("%u/n",b);
printf("%x/n",b);
}
21、u_long PASCAL FAR ntohl( u_long netlong);
将一个无符号长整形数从网络字节顺序转换为主机字节顺序。
参数netlong:一个以网络字节顺序表达的32位数。
返回值:ntohl()返回一个以主机字节顺序表达的数。
//将32位网络字节转换为主机字节,使用函数ntohl()
//定义如下 u_long ntohl(u_long netlong);
#include <WINSOCK2.H>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
u_long a = 0x12345678;
u_long b = ntohl(a);
printf("%u/n",a);
printf("%x/n",a);
printf("%u/n",b);
printf("%x/n",b);
}
22、int PASCAL FAR getpeername( SOCKET s, struct sockaddr FAR* name, int FAR* namelen);
参数s:标识一已连接套接口的描述字。
参数name:接收端地址的名字结构。
参数namelen:一个指向名字结构的指针。
getpeername()函数用于从端口s中获取与它捆绑的端口名,并把它存放在sockaddr类型的name结构中。 它适用于数据报或流类套接口。 返回值: 若无错误发生,getpeername()返回非零。否则的话,返回0,应用程序可通过WSAGetLastError()来获取相应的错误代码。
23、int PASCAL FAR getsockname( SOCKET s, struct sockaddr FAR* name, int FAR* namelen); 获取一个套接口的本地名字。
s:标识一个已捆绑套接口的描述字。
name:接收套接口的地址(名字)。
namelen:名字缓冲区长度。
getsockname()函数用于获取一个套接口的名字。 它用于一个已捆绑或已连接套接口s,本地地址将被返回。
本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。 在返回时,namelen参数包含了名字的实际字节数。 若一个套接口与INADDR_ANY捆绑,也就是说该套接口可以用任意主机的地址, 此时除非调用connect()或accept()来连接,否则getsockname()将不会返回主机IP地址的任何信息。 除非套接口被连接,WINDOWS套接口应用程序不应假设IP地址会从INADDR_ANY变成其他地址。 这是因为对于多个主机环境下,除非套接口被连接,否则该套接口所用的IP地址是不可知的。 返回值: 若无错误发生,getsockname()返回0。 否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
附:22、23函数中错误代码:
WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。
WSAEFAULT:namelen参数不够大。
WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
WSAENOTCONN 套接口未连接。
WSAENOTSOCK:描述字不是一个套接口。
WSAEINVAL:套接口未用bind()捆绑。
24、int PASCAL FAR setsockopt( SOCKET s, int level, int optname, const char FAR* optval, int optlen);
关于该函数的介绍请参考下面连接:http://blog.sina.com.cn/s/blog_a459dcf5010155nb.html
25、int PASCAL FAR getsockopt( SOCKET s, int level, int optname, char FAR* optval, int FAR* optlen);
关于该函数的介绍请参考下面连接:http://blog.sina.com.cn/s/blog_a459dcf5010155nb.html