什么是套接字(Socket),套接字的流程是什么
套接字通常用于客户端和服务器交互。典型的系统配置将服务端放在一台计算机上,而客户端放在其他计算机上。客户端连接到服务器,交换信息,然后断开连接。
根据RFC793的定义:端口号拼接到IP地址就构成了套接字。套接字Socket=(IP地址:端口号)。
套接字具有典型的事件流。在面向连接的客户机到服务器模型中,服务器进程上的套接字等待来自客户机的请求。为此,服务器首先建立一个地址,客户端可以使用该地址来查找服务器。建立地址后,服务器将等待客户端请求服务。当客户端通过套接字连接到服务器时,会发生客户端到服务器的数据交换。服务器执行客户机的请求并将回复发送回客户机。
套接字通信流程 |
---|
服务器 | 客户机 |
---|---|
socket( ) | socket( ) |
bind( ) | bind( ) (可选) |
listen( ) | |
connect( ) | |
accpet( ) | |
send( )、recv( )、read( )、write( ) | send( )、recv( )、read( )、write( ) |
close( ) | close( ) |
注:在winsock2中,程序在创建套接字之前要对Windows Sockets DLL进行初始化:
创建一个类型为WSADATA的对象,再 WSAStartup ( MAKEWORD(2,2) , 前面对象的内存地址) ;
成功初始化后函数会返回0。
同样,在使用完套接字后要调用WSACleanup();对其注销。该函数无参数,成功注销后会返回0。
创建套接字 socket( )
SOCKET PASCAL FAR socket ( int af, int type, int protocol ) ;
创建一个用于通信的端点,并返回一个表示该端点的描述符。
参数 af、type、protocol分别表示协议族、通信类型、协议端口。
协议族:AF_INET(ARPA因特网协议)[用于windows,dos]、AF_UNIX(UNIX域协议)[用于UNIX,linux]、AF_ISSO(ISO标准协议)、AF_NS(Xerox网络协议)、AF_IPX(Novell IPX协议)、AF_APPLETALK (Appletalk DDS协议)
通信类型:数据流TCP(SOCK_STREAM)、数据报UDP(SOCK-DGRAM)、原始类型(S0CK_RAW)
端口:设为0表示默认协议
当套接字创建成功后会返回一个套接字描述符。若失败,则返回 INVALID_SOCKET
命名套接字 bind( )
int PASCAL FAR bind ( int socket, const struct sockaddr *address, size_t address_len ) ;
当套接字成功创建得到一个套接字描述符时,服务器必须在listen( )执行之前通过描述符为该套接字命名。
参数 socket、*address、address_len分别表示套接字描述符、指向套接字地址结构体的指针、套接字地址结构长度。
注:在AF_INET域中,套接字地址结构由sockaddr_in来指定
struct sockaddr_in {
short int sin_family; //套接字域
unsigned short int sin_port; //接口
struct in_addr sin_addr;
}
IP地址结构in_addr被定义如下:
struct in_addr {
unsigned long int s_addr;
};
成功时,bind( )返回0,否则返回-1。
创建套接口以监听连接 listen( )
int listen ( int sockfd, int backlog ) ;
服务器为了接受客户端的连接请求,必须通过listen( )来创建一个队列来保存未处理的请求。在accept( )执行前必须执行listen( )。
参数 sockfd、backlog分别表示套接字描述符、等待连接队列最大长度。
当客户端连接请求一个队列已满的套接口会收到一个WSAECONNREFUSED错误。
成功时,listen( )返回0,否则返回-1。
连接请求 connect( )
int connect ( SOCKET s, const struct sockaddr * name, int namelen ) ;
客户程序通过一个未命名套接字与指定的socket建立连接。
参数 s、*name、namelen分别表示未命名的套接字、指向所要连接的套接字地址结构的指针、套接字地址结构长度
接受连接 accept( )
SOCKET accept ( int sockfd, struct sockaddr *addr, socklen_t *addrlen ) ;
在listen( )执行后,服务器收到来自客户端的连接请求时,就可以通过accept( )从套接口的等待队列中对第一个请求作出应答。
参数 sockfd、*addr、*addrlen分别表示服务器套接字描述符、指向用于存放客户地址结构的指针、客户地址结构的长度
addr、addrlen为返回参数,当accept( )成功执行后会返回一个新的套接字描述符(该描述符与客户端中的描述符是相同的,并包含客户端、服务器的套接字地址结构信息)。之后的通信就用这个新的套接字描述符,而服务器原套接字描述仍再进行监听。
断开连接 close( ) / closesocket( )
int PASCAL FAR closesocket ( SOCKET s ) ;
终止一个通信,并释放相应的名字、队列信息。
参数 s 表示所要释放的套接字