快要放假了,不怎么想工作,写写博客。这两天简单看了一些socket的相关知识,做下总结。
一、socket介绍
套接字描述符,是通信端点的抽象。一开始时学习socket只认为可以用在网络通信上,这次才发现也可以用在本地中,可以作为进程间通信来使用。只是在建立socket上一些常量做下改变就可以了。
首先创建socket的函数有socket()和socketpair();
int socket(int domain, int type, int protocol);
这里的domain和type有不同的选择,创建的socket也不同。
(当然还有其他类型,可以自己查阅)
域名为PF_INET和PF_UNIX (其中对于BSD,是AF,对于POSIX是PF),type是流类型tcp和数据报udp。
对于本地的socket建立一般可以使用socketpair()
int socketpair(int d, int type, int protocol, int sv[2]);
socketpair()函数建立一对匿名的已经连接的套接字,其特性由协议族d、类型type、协议protocol决定,建立的两个套接字描述符会放在sv[0]和sv[1]中。
第1个参数d,表示协议族,只能为AF_LOCAL或者AF_UNIX;
第2个参数type,表示类型,只能为0。
第3个参数protocol,表示协议,可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STREAM建立的套接字对是管道流,与一般的管道相区别的是,套接字对建立的通道是双向的,即每一端都可以进行读写。
二、寻址
当建立好socket后,接下来的工作就是明确本地的地址,对于主动连接的那一端来说还多一个要连接的目的端地址。这个地址是放在一个结构体里的 struct sockaddr。
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
套接字实现可以自由的添加额外的成员并且定义sa_data成员大小。
在linux下
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};
因特网地址定义在
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
三、相关函数
当上述的socket和地址都确定好之后,就开始将他们两绑定用bind()函数;
int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen)
当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。
1、
int listen(int sockfd,int backlog)
udp没有此函数。
2、
int connect(int sockfd,conststruct sockaddr *addr, socklen_t addrlen)
通过此函数建立于TCP服务器的连接,实际是发起三次握手过程,仅在连接成功或失败后返回。参数sockfd是本地描述符,addr为服务器地址,addrlen是socket地址长度。
UDP的connect函数,结果与tcp调用不相同,没有三次握手过程。内核只是记录对方的ip和端口号,他们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。
3、
accept
intaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
4、
ssize_t send(int sockfd,constvoid *buf, size_t len,int flags)
5、
ssize_t sendto(int sockfd,const void *buf, size_t len, int flags,const struct sockaddr *dst_addr, socklen_t addrlen);
6、
ssize_t recv(int sockfd,void *buf, size_t len,int flags)
其中:
sockfd:接收端套接字描述符;
buf:指定缓冲区地址,用于存储接收数据;
len:指定的用于接收数据的缓冲区长度;
flags:一般指定为0
表示从接收缓冲区拷贝数据。成功时,返回拷贝的字节数,失败返回-1。阻塞模式下,recv/recvfrom将会阻塞到缓冲区里至少有一个字节(TCP)/至少有一个完整的UDP数据报才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1,置错误码为EWOULDBLOCK。
7、
ssize_t recvfrom(int sockfd,void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)
sockfd:接收端套接字描述
buf:用于接收数据的应用缓冲区地址
len:指名缓冲区大小
flags:通常为0
src_addr:数据来源端的地址
addrlen:src_addr地址的长度
注意后两个参数是输出参数,其中addrlen既是输入又是输出参数,即值-结果参数,需要在调用时,指明src_addr的长度。另外,如果不关心数据发送端的地址,可以将后两者均设置为NULL。
8. close
close缺省功能是将套接字作“已关闭”标记,并立即返回到调用进程,该套接字描述符不能再为该进程所用:即不能作为read和write(send和recv)的参数,但是TCP将试着发送发送缓冲区内已排队待发的数据,然后按正常的TCP连接终止序列进行操作(断开连接4次握手-以FIN为首的4个TCP分节)。
- shutdown
shutdown不仅可以灵活控制关闭连接的读、写或读写功能,而且会立即执行相应的断开动作(发送终止连接的FIN分节等),此时不论有多少进程共享此套接字描述符,都将不能再进行收发数据。