sa_family_t sun_family;
char sun_path[UNIX_PATH_MAX];
2、调用bind()函数,将创建的socket对象与bind()函数产生的那个socket类型的文件server_socket P绑定。
UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,其地址用结构体sockaddr_un表示, 网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,且已被link,则bind()错误返回。一个套接字只能绑定到一个路径上,同样的,一个路径也只能被一个套接字绑定。
sockaddr_un结构的sun_path成员包含一路径名,当我们将一地址绑定至UNIX域套接字时,系统用该路径名创建一类型为S_IFSOCK的文件。该文件仅用于向客户端进程告知套接字名字,该文件不能打开,也不能由应用程序用于通信,当关闭套接字时,并不自动删除该文件,所以我们必须确保在应用程序终止前,对该文件执行解除链接操作(unlink(path)),或删除该文件。
struct sockaddr_un结构有两个参数:sun_family、sun_path。sun_family只能是AF_LOCAL或AF_UNIX;而sun_path就是本地文件的路径。存放文件路径的sun_path数组必须以空字符(即’\0’字符)结尾
4、服务器端监听到该请求,在客户端发出请求后,accept()函数接收请求,返回新文件描述符,从而建立连接。
5、服务器端调用read()函数接收数据(开始处于阻塞状态,等待客户端发送数据,因此,客户端在编程是需要首先发送数据,接收到数据后,输出接收到的数据)。
7、通信完成后,调用close()函数关闭socket对象;unlink(sockaddr_un.sun_path)。
3、在得到服务器端允许后,首先调用write()函数向服务器端发送消息(因服务器端循环体中首先是接收数据)。
成功调用 pipe 函数之后,可以对写入端描述符 pipefd[1] 调用 write ,向管道里面写入数据,比如
· 只有当所有的写入端描述符都已关闭,且管道中的数据都被读出,对读取端描述符调用 read 函数
· 如果所有读取端描述符都已关闭,此时进程再次往管道里面写入数据,写操作会失败, errno 被设
命名管道就是为了解决无名管道的这个问题而引入的。 FIFO 与管道类似,最大的差别就是有实体
文件与之关联。由于存在实体文件,不相关的没有亲缘关系的进程也可以通过使用 FIFO 来实现进程之
上; 对 FIFO 文件推荐的使用方法是,两个进程一个以只读模式( O_RDonLY )打开 FIFO 文件,另一个以只写模式( O_WRonLY )打开 FIFO 文
个字节,你无法确认这 100 个字节是单次写入的 100 字节,还是分 10 次每次 10 字节写入的,你也无法知
晓这 100 个字节是几个消息。管道或 FIFO 里的数据如何解读,完全取决于写入进程和读取进程之间的约
System V 消息队列比管道或 FIFO 优越的第二个地方在于每条消息都有 type 字段,消息的读取进程可
以通过 type 字段来选择自己感兴趣的消息,也可以根据 type 字段来实现按消息的优先级进行读取,而不
共享内存是所有 IPC 手段中最快的一种。它之所以快是因为共享内存一旦映射到进程的地址空间,
回顾一下前面已经讨论过的管道、 FIFO 和消息队列,任意两个进程之间想要交换信息,都必须通
· 发送信息的一方,通过系统调用( write 或 msgsnd )将信息从用户层拷贝到内核层,由内核暂存这
· 提取信息的一方,通过系统调用( read 或 msgrcv )将信息从内核层提取到应用层
epoll 或者 select 处理事件时,可读事件时,read返回值-1,如果errno不为EAGAIN,可以认为失败,并关闭fd。read返回0,说明对方断开连接,此时也需要关闭fd。如果链路断了,如拔掉网线,需要是用keepalive来触发可写事件
本地UDP发送过快也是会丢包的。非阻塞情况下的unix domain socket哪怕是STREAM的也是会丢包的
使用unix socket通信相比于本地udp通信减少了校验和的计算。使用阻塞函数时,unix domain socket可以保证不丢包不乱序,但是当发送缓冲区满了的话则会阻塞。使用非阻塞操作时经测试会丢包
使用setsockopt设置发送缓冲时,SO_RCVBUF和SO_SNDBUF的最大值受系统设置限制,可以使用SO_RCVBUFFORCE和SO_SNDBUFFORCE来无视系统设置
SIGPIPE信号,网络编程时一定要处理该信号。同样一般要设置的还有SO_REUSEADDR。当客户端close连接时,若server继续发送数据,会收到RST,继续写就会SIGPIPE
网络编程对事件进行封装,提供注册回调函数,在可读、可写时进行函数调用。一般用法,针对非阻塞情况,初始化时将可读事件注册,需要写的时候先写,写不下去的时候(errno=EAGAIN)再挂上可写事件,只要发送缓冲区还有空间,就是可写的
基于事件的编程框架,需要记录最后一次成功read或write的时间,如果idletime大于阈值,直接close
服务器编程可以设置最大的fd个数,然后一次性申请FileEvent数组,之后由fd到事件查询代价O(1)
针对非阻塞socket,connect返回EINPROGRESS时需要将fd加到可写事件监视集合中,当select()或者poll()返回可写事件时,需要用getsockopt去读SOL_SOCKET层面的SO_ERROR选项,SO_ERROR为0表示连接成功,否则为连接失败
epoll ET模式的处理方式。读:只要可读就一直读,一直读到返回0,或者error = EAGAIN。写:只要可写就一直写,知道数据发送完,或者errno = EAGAIN
socket read缓冲区最大值TCP可查看”/proc/sys/net/ipv4/tcp_rmem”, udp 65536
实现定时器时通常办法是select/poll/epoll接口,精度毫秒级;还有就是新增的系统调用timerfd_create 把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,高于poll的精度
在主动关闭连接时,可以先shutdown(fd, SHUT_WR)关闭写端,等对方close时再关闭读端。这样子的好处是如果对方已经发送了一些数据,这些数据不会漏收。这就要求对端在read返回0之后关闭连接或者shutdown写端
网络编程一种比较好的模型是“one loop per thread”,如果事件库不是线程安全的,则需要使用pipe或者
socketpair通知,子线程接受到通知(fd可读)后处理,kernel 2.6.22加入了eventfd,是更好的通知方法
TCP Nagle算法和TCP Delayed Ack机制可能会导致网络延时(Linux 40ms, Windows 200ms),最容易产生问题的就是Write-Write-Read”这种模型,发送端的Nagle算法和接收端的Delayed Ack会导致一直等到接收端delayed ack超时后数据才发送出去
accept返回EMFILE,进程描述符用完了,无法创建新的socket,也无法close连接,会导致不断通知该可读事件,程序busy loop,cpu 100%,解决方法是事先准备一个nullfd=open(“/dev/null”),close该fd,accept,close socket,然后再nullfd=open(“/dev/null”),缺点是该方法线程不安全,多线程accept可能导致nullfd用于新socket创建,然后又处于busy loop中

