0
点赞
收藏
分享

微信扫一扫

unix socket unix|unix_dgram|unix_stream|unix_seqpacket

q松_松q 2022-12-05 阅读 154

  在使用ss 查socke 状态时,突然发现unix socket中存在unix|unix_dgram|unix_stream|unix_seqpacket 这三种类型,于是看了相关资料。

看了一下stackoverflow 相关知识!

  The main difference is that one is connection based (​​STREAM​​) and the other is connection-less (​​DGRAM​​) - the difference between stream and packet oriented communication is usually much less important.

With ​​SOCK_STREAM​​​ you still get all the connection handling, i.e. ​​listen​​​/​​accept​​ and you can tell if a connection is closed by the other side.

Note that there is also a ​​SEQPACKET​​​ socket type that's still connection oriented, but preserves message boundaries (which might save you from implementing a message-oriented layer on top of a ​​STREAM​​ socket).

I would expect data transfer performance to be similar for all of these types, the main difference is just what semantics you want.

  Stream socket allows for reading arbitrary number of bytes, but still preserving byte sequence. In other words, a sender might write 4K of data to the socket, and the receiver can consume that data byte by byte. The other way around is true too - sender can write several small messages to the socket that the receiver can consume in one read. Stream socket does not preserve message boundaries.

Datagram socket, on the other hand, does preserve these boundaries - one write by the sender always corresponds to one read by the receiver (even if receiver's buffer given to ​​read(2)​​​ or ​​recv(2)​​ is smaller then that message).

So if your application protocol has small messages with known upper bound on message size you are better off with ​​SOCK_DGRAM​​ since that's easier to manage.

If your protocol calls for arbitrary long message payloads, or is just an unstructured stream (like raw audio or something), then pick ​​SOCK_STREAM​​ and do the required buffering.

Performance should be the same since both types just go through local in-kernel memory, just the buffer management is different.

也就是stream socket 是流模式, 不存在边界,发送端发送4k,接收端可以1个字节一个字节的接收;使用时候也需要使用listen connect等系统调用

Datagram socket包模式:存在边界,必须一个包一个包的接收

  1. One likely difference are message boundaries. Datagrams will be delivered as a whole with the datagrams being the natural message boundaries. With stream sockets you can read N bytes and the socket will block until N bytes are ready. But this means no obvious message boundaries.
  2. All things being equal, if speed is a concern, instrument and measure. (I assume you already know that only a stream socket provides built-in reliable in-order transport, and only datagram sockets can be used to send to multiple receivers).

 

SOCK_STREAM类型的socket是一个全双工的字节流,不预留消息边界:

  • 一个stream socket必须处于连接状态才能收发数据;
  • 通过调用​​connect()​​函数来连接到另一个创建的socket;
  • 一旦连接建立起来了,就可以通过​​read()​​​和​​write()​​函数调用来进行数据传输了;
  • 最后调用​​close()​​函数关闭连接;
  • 实现了SOCK_STREAM的通信协议栈确保数据不会丢失或者重复;

 

​​具体样例参考:见IBMhttps://www.ibm.com/docs/en/ztpf/1.1.0.15?topic=considerations-unix-domain-sockets​​

对于Datagram socket包模式; 接收端必须一个一个报的接收, 每次调用read(fd)接收报文, 如果buf不够, 比如client 发送了20字节数据, 但是此次只有10bytes的buff,

此时调用read后,只会返回前10 bytes,后续的报文不会收到, 内核也会将此报文完整丢弃,

static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
struct scm_cookie scm;
struct sock *sk = sock->sk;
struct unix_sock *u = unix_sk(sk);
int noblock = flags & MSG_DONTWAIT;
struct sk_buff *skb;
int err;
int peeked, skip;

err = -EOPNOTSUPP;
if (flags&MSG_OOB)
goto out;

err = mutex_lock_interruptible(&u->iolock);
if (unlikely(err)) {
/* recvmsg() in non blocking mode is supposed to return -EAGAIN
* sk_rcvtimeo is not honored by mutex_lock_interruptible()
*/
err = noblock ? -EAGAIN : -ERESTARTSYS;
goto out;
}

skip = sk_peek_offset(sk, flags);

skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
if (!skb) {
unix_state_lock(sk);
/* Signal EOF on disconnected non-blocking SEQPACKET socket. */
if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN &&
(sk->sk_shutdown & RCV_SHUTDOWN))
err = 0;
unix_state_unlock(sk);
goto out_unlock;
}

wake_up_interruptible_sync_poll(&u->peer_wait,
POLLOUT | POLLWRNORM | POLLWRBAND);

if (msg->msg_name)
unix_copy_addr(msg, skb->sk);

if (size > skb->len - skip)
size = skb->len - skip;
else if (size < skb->len - skip)
msg->msg_flags |= MSG_TRUNC;

err = skb_copy_datagram_msg(skb, skip, msg, size);
if (err)
goto out_free;

if (sock_flag(sk, SOCK_RCVTSTAMP))
__sock_recv_timestamp(msg, sk, skb);

memset(&scm, 0, sizeof(scm));

scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
unix_set_secdata(&scm, skb);

if (!(flags & MSG_PEEK)) {
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);

sk_peek_offset_bwd(sk, skb->len);
} else {
/* It is questionable: on PEEK we could:
- do not return fds - good, but too simple 8)
- return fds, and do not return them on read (old strategy,
apparently wrong)
- clone fds (I chose it for now, it is the most universal
solution)

POSIX 1003.1g does not actually define this clearly
at all. POSIX 1003.1g doesn't define a lot of things
clearly however!

*/

sk_peek_offset_fwd(sk, size);

if (UNIXCB(skb).fp)
scm.fp = scm_fp_dup(UNIXCB(skb).fp);
}
err = (flags & MSG_TRUNC) ? skb->len - skip : size;

scm_recv(sock, msg, &scm, flags);

out_free:
skb_free_datagram(sk, skb);// 直接释放skb
out_unlock:
mutex_unlock(&u->iolock);
out:
return err;
}

对于:unix_seqpacket??

直接看内核中unix-seqpacket的读写操作函数

static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
struct sock *sk = sock->sk;

if (sk->sk_state != TCP_ESTABLISHED)
return -ENOTCONN;

return unix_dgram_recvmsg(sock, msg, size, flags);
}

也就是 unix_seqpacket  == unix_dgram + connect  ??提供一种有序的,可靠的,双向的基于连接的Datagrams 传输数据报文,报文的最大大小固定

  • SOCK_STREAM:提供一种有序的,可靠的,双向的,基于连接的字节流
  • SOCK_DGRAM:支持数据报文(非连接的,不可靠的具有固定的最大字节长度的消息)
  • SOCK_SEQPACKET:提供一种有序的,可靠的,双向的基于连接的数据传输通道传输数据报文,报文的最大大小固定

http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子



举报

相关推荐

0 条评论