1、套接字主要函数介绍:
套接字函数通常封装在Ws2_32.dll动态连接库中,头文件是winsock2.h,因此用户需要引用头文件和链接库
#include “winsock.h” //引用头文件
#pragma comment(lib,”ws2_32.lib”) //链接库文件
此外,使用套接库函数前需要初始化套接字,使用函数WSAStartup()实现,例如:
WSADATA wsd; //定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd); //初始化套接字
下面介绍一些套接字函数
1:WSAStartup函数:用于初始化动态连接库,而且不可或缺
int WSAStartup(WORD wVersionRequested,LPWSADATA lpWDADATA)
//用法参见前面几行代码
2:socket函数:用于创建一个套接字
SOCKET socket(int af, int type, int protocol)
Af:表示一个地址家族,通常是AF_INET
type:表示套接字类型,SOCK_STREAM:创建面向连接的流式套接字;SOCK_DGRAM:表示创建面向无连接的数据报套接字,SOCK_RAW:表示创原始套接
protocol:表示所用的协议,不指定时可以设置为0
函数的返回值是创建的套接字句柄。
3:bind函数:用于将套接字绑定到指定的端口和地址上
int bind(SOCKET s,const struct sockadddr FAR * name, int namelen)
s:表示套接字标志
name:是一个sockaddr结构指针,包含了端口和地址
namelen:确定name缓冲区长度
返回值:成功返回0;失败返回SOCKET_ERROR
4: listen函数:用于将套接字设置为监听模式。对于流式套接字必须是该模式
Int listen(SOCKET s, int backlog)
Backlog: 表示等待连接的最大队列长度
5:accept函数:用于接收客户端的链接
SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR * addlen)
S:一个套接字标志,应该处于监听状态
addr:包含一组客户端的端口和地址信息
addlen:用于接收参数addr的长度
返回值:一个新的套接字,它对应于已经接受的客户端连接,对于该客户端的所有后续操作,都应该使用这个新的套接字。
6:closesocket函数:关闭套接字。int closesocket(SOCKET s);
7:connect函数:用于发送一个连续请求
int connect(SOCKET s, const struct sockaddr FAR * name, int namelen)
name:表示套接字想链接的主机地址和端口号
namelen:表示缓冲区长度
成功返回0,否则为SOCKET_ERROR。
8:recv函数:用于从面向连接的套接字中接收数据
int recv(SOCKET s, char FAR *buf,int len, int flags)
buf:接收数据的缓冲区
len:buf的长度
flags表示函数的调用方式 MSG_PEEK:表示查看传来的数据,MSG_OOB表示用来处理外带数据
9:send函数:用于在面向连接方式的套接字间发送数据
int send(SOCKET s, const char FAR * buf, int len, int flags)
buf要发送数据缓冲区的大小
flags函数的调用方式
10:select函数:用来检查一个或多个套接字是否处于可读、可写或错误状态
Int select(int nfds,fd_set FAR *readfds, fd_set FAR *writefds,fd_set FAR * exceptfds, const struct timeval FAR * timeout)
nfds:无实际意义
readfds表示一组可读套接字
writefds表示一组可写套接字
exceptfds表示一组被检查有错误的套接字
timeout表示函数的等待时间
11:WSACleanup函数:用于释放从Ws2_32.dll动态连接库初始化分配的资源
Int WSACleanup(void)
2、套接字网络编程
1.什么是套接字
应用程序利用套接字在网络上发送或接收数据包。常用的套接字类型有:流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。流式Socket是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
2.创建套接字对象
Socket函数可创建一个套接字对象,该函数返回一个类似于文件描述符的句柄。socket函数原型为:
SOCKET socket(int domain, int type, int protocol);
参数含义:
domain指明所使用的协议族,通常为 AF_INET,表示互联网协议族(TCP/IP协议族);
type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM;
protocol通常赋值"0"。
Socket()调用返回一个整型socket描述符。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。
###创建套接字socket之后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。
3.绑定端口
Bind函数为服务器端定义的socket指定一个网络地址及端口,这样客户端才知道稍后要连接哪一个地址的那个端口,发出请求;服务器在该端口监听服务请求。Bind函数原型为:
int bind(SOCKET s,struct sockaddr *my_addr, int addrlen);
参数含义:
s:调用socket函数返回的socket描述符;
my_addr:一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
addrlen:my_addr的长度,常被设置为sizeof(struct sockaddr)。
其中,struct sockaddr结构说明如下:
struct sockaddr_in {
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP地址 */
unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */
};
使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没被占用的端口号:
my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */
my_addr.sin_addr.s_addr = INADDR_ANY; /* 系统会自动填入本机IP地址 */
4.建立套接字连接
客户端程序的socket使用Connect函数与服务器端的socket建立连接申请,Connect函数在调用成功返回0,出现错误时返回SOCKET_ERROR.其函数原型为:
int connect(SOCKET s, struct sockaddr *serv_addr,int addrlen);
参数含义:
s:进行连接的socket描述符;
serv_addr:包含远端主机IP地址和端口号的指针;
addrlen:是远端地址结构的长度。
对于服务器来说,当客户端发来连接请求时,服务器要调用accept()函数来响应对方的请求,该函数原型如下:
SOCKET accept(SOCKET s, void *addr, int *addrlen);
参数含义:
s:本地socket描述符;
addr:addr通常是一个指向sockaddr_in变量的指针,用来存放提出连接请求的客户端地址;
addrten:通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。
accept返回一个与s用相同特性的新SOCKET类型的值,用于处理服务器请求。
5.监听连接
当服务器端的socket对象绑定之后,服务端必须建立一个监听的队列来接收客户端请求。listen()函数使得服务器端的socket进入监听状态。函数原型如下:
int PASCAL FAR listen(SOCKET s, int backlog);
参数含义:
s:需要建立监听的socket;
backlog:最大连接个数。
6.数据传输
连接建立以后,可以进行数据传输。数据传输包括数据发送和数据接收。
格式:int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);
int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);
参数:buf:指向存有传输数据的缓冲区的指针。
7、多路复用——select()
功能:用来检测一个或多个套接字状态。
格式:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,
fd_set FAR * exceptfds,const struct timeval FAR * timeout);
参数:readfds:指向要做读检测的指针
writefds:指向要做写检测的指针
exceptfds:指向要检测是否出错的指针
timeout:最大等待时间
8、关闭套接字——closesocket()
功能:关闭套接字s
格式:BOOL PASCAL FAR closesocket(SOCKET s);
由于每个套接字描述符都对应一个位于操作系统缓冲区中的套接字数据结构,有可能几个套接字描述符指向同一个套接字数据结构,因此该结构中专门有一个字段存放其被引用的次数。当调用closesocket时,如果该字段为1,表明只有一个描述符指向它,在描述符表中将对应的描述符记清除,并且释放s对应的套接字数据结构;如果大于1,仅仅清除对应的描述符,并且把s对应的套接字数据结构的引用次数减1。
面向连接的套接字编程一般流程: