socket()
函数原型如下:
#include <sys/types.h>
#include <sys/socket.h>
/*************
*domain:指定协议族,常用的为AF_INET/AF_INET6
*type:套接字类型:SOCK_STREAM/SOCK_DGRAM/SOCK_RAW
*protocol:指定网络传输协议类型,type已经确定网络传输协议的类型,所以常常置0
**************/
int socket (int domain,int type,int protocol)
socket()函数执行成功时候,返回一个小的非负整数值,类似于文件描述符,称为套接字描述符,简称sockfd;使用socket函数后,指定了套接字的协议族和类型;
bind()
函数原型如下:
#include <sys/types.h>
#include <sys/socket.h>
/*************
*sockfd:调用socket()返回的sockfd
*my_addr:指向本地套接字地址结构的指针
*addrlen:sizeof(struct sockaddr)
**************/
int bind(int sockfd,const struct sockaddr *my_addr,int addrlen)
bind()函数将一个本地协议地址(IP地址+端口号)赋予一个套接字;调用bind函数可以指定一个端口号,或者一个IP地址,也可以两者都指定,或者两者都不指定,当不使用bind绑定端口号时,内核就会回相应的套接字选择一个临时的端口号;服务器和客户端程序都可以使用bind绑定本地协议地址到自己的套接字上;
通配符:指定套接字地址中的IP地址为通配符地址(INADDR_ANY),内核将会选择一个本地IP地址最为套接字地址结构中的IP地址;
connect()
函数原型如下:
#include <sys/types.h>
#include <sys/socket.h>
/*************
*sockfd:调用socket()返回的sockfd
*serv_addr:指向远程主机的套接字地址结构的指针
*addrlen:sizeof(struct sockaddr)
**************/
int connect(int sockfd,struct sockaddr *serv_addr,int addrlen)
TCP客户端使用connect函数来建立TCP服务器的连接;如果是TCP套接字,调用connect函数将激发TCP的三次握手;若connect函数调用失败,该套接字不再可用,必须使用close关闭;若调用成功,当前套接字从CLOSED状态转移到SYN_SENT状态,再转移到ESTABLISHED状态;
listen()
函数原型如下:
#include <sys/socket.h>
/*************
*sockfd:调用socket()返回的sockfd
*backlog:已经握手成功的队列的最大数目
**************/
int listen(int sockfd,int backlog)
listen()函数等待别人连接,进行系统侦听请求的函数;调用listen ()函数,导致套接字从CLOSED状态转换到LISTEN状态;
accept()
函数原型如下:
#include <sys/socket.h>
/*************
*sockfd:调用socket()返回的sockfd
*addr:指向已连接的对端进程的协议地址
*addrlen:协议地址的大小
**************/
int accept(int sockfd,void *addr,int *addrlen)
accept函数有TCP服务器调用,用于从已完成连接的队列头返回写一个已完成的连接,如果已完成队列连接为空,进程阻塞进入睡眠;accept函数调用成功后,由内核返回一个全新的套接字描述符,代表与所返回的客户的TCP连接;函数的第一个参数sockfd称为监听套接字,新生成的套接字描述符称为已连接的套接字描述符,代表一个TCP连接(TCP是面向连接的传输服务)
read()和write()
使用常用的系统调用函数read()和write()对套接字描述符进行访问,不同的是,套接字在内核中使用阻塞方式进行访问,read()和write()函数读取和写入的字节数可能比请求中的少(比如,套接字中的缓冲区的可写入的空间少于请求写入的字节数或者套接字中的缓冲区的可读取的字节数少于请求读取的字节数),所以我们采取循环操作的方法,多次调用read()和write()函数完成操作,具体的函数,在《UNIX网络编程卷1》中有实现的函数readn()和writen()函数可供使用和参考;初次之外,socket编程提供了其他的输入输出操作函数,比如:send()和recv()函数,在下文总结;
send()和recv()
函数原型如下:
#include <sys/types.h>
#include <sys/socket.h>
/*************
*sockfd:已连接套接字描述符
*msg:指向发送空间的指针
*len:需要发送的字节数
*flags:发送标记
**************/
int send(int sockfd,const void *msg,int len,int flags)
/*************
*sockfd:已连接套接字描述符
*buf:存放数据的内存缓冲区地址
*len:缓冲区的大小,防止缓冲区越界存储
*flags:接受标志
**************/
int recv(int sockfd,void *buf,int len,unsigned int flags)
send()函数返回真正发送数据的长度,另外,send()函数所发送的数据可能少于函数参数中指定的长度,此时,需要判断函数的返回值,返回值小于指定的长度,需要再次调用send()函数进行发送,知道全部发送完成,一般小于1k的数据,send()函数会一次发送完成;
recv()函数返回真正接收到的数据长度;
sendto()和recvfrom()
函数原型如下:
#include <sys/types.h>
#include <sys/socket.h>
/*************
*sockfd:与远程连接的套接字描述符
*msg:指向发送空间的指针
*len:需要发送的字节数
*flags:发送标记
*to:远程主机的协议地址(IP地址+端口号)
*tolen:sizeof(struct sockaddr)
**************/
int sendto(int sockfd,const void *msg,int len,unsigned int flags,const sruct sockaddr *to,int tolen)
/*************
*sockfd:与远程连接的套接字描述符
*buf:存放数据的内存缓冲区地址
*len:缓冲区的大小,防止缓冲区越界存储
*flags:发送标记
*from:一个本地协议地址指针,用来存放远程主机的协议地址(源IP地址+端口号)
*tolen:sizeof(struct sockaddr)
**************/
int recvfrom(int sockfd,const void *buf,int len,unsigned int flags,const sruct sockaddr *from,int fromlen)
这两个函数是进行无连接的UDP通讯时使用的,一种无连接的传输,也可以使用connect+send/recv函数来替代sendto和recvfrom,此时,客户和主机都是数据包类型的套接字;
close()和shutdown()
close()函数原型如下:
#include <unistd.h>
/*************
*sockfd:已连接套接字或者侦听套接字
**************/
int close(int sockfd)
shutdown()函数原型如下:
#include <sys/socket.h>
/*************
*sockfd:已连接套接字或者侦听套接字
*how:0:不允许套接字接收数据 1:不允许套接字发送数据 2:不允许发送和接收,双向关闭
*************/
int shutdown(int sockfd,int how)