Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65214
  • 博文数量: 11
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-06 15:04
文章分类
文章存档

2018年(11)

我的朋友

分类: LINUX

2018-04-08 15:29:52

上一篇简单说了服务器端接收,在客户端发起连接之前,服务器只是再监听自己的接收队列,在没有数据时把进程切换出去,等待连接,这篇文章说一下客户端连接
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sun_family = AF_UNIX;
  strncpy(server_addr.sun_path, argv[1], sizeof(server_addr.sun_path));
ret = connect(sockfd, (struct sockaddr *)&server_addr, addrlen);
客户端需要把想连接的地址写如第二个参数中去, unix socket就是服务器的监听地址


点击(此处)折叠或打开

  1. SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
  2.         int, addrlen)
  3. {
  4.     struct socket *sock;
  5.     struct sockaddr_storage address;
  6.     int err, fput_needed;
  1.     sock = sockfd_lookup_light(fd, &err, &fput_needed); // 根据socket描述符找到socket结构
  2.     if (!sock)
  3.         goto out;
  4.     err = move_addr_to_kernel(uservaddr, addrlen, &address); //拷贝服务器地址
  5.     if (err < 0)
  6.         goto out_put;

  7.     err =
  8.      security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
  9.     if (err)
  10.         goto out_put;

  11.     err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
  12.                  sock->file->f_flags);
  13. out_put:
  14.     fput_light(sock->file, fput_needed);
  15. out:
  16.     return err;
  17. }
unix SOCK_STREAM socket 调用 unix_stream_connect


点击(此处)折叠或打开

  1. static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
  2.              int addr_len, int flags)
  3. {
  4.     struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
  5.     struct sock *sk = sock->sk;
  6.     struct net *net = sock_net(sk);
  7.     struct unix_sock *u = unix_sk(sk), *newu, *otheru;
  8.     struct sock *newsk = NULL;
  9.     struct sock *other = NULL;
  10.     struct sk_buff *skb = NULL;
  11.     unsigned int hash;
  12.     int st;
  13.     int err;
  14.     long timeo;

  15.     err = unix_mkname(sunaddr, addr_len, &hash);
  16.     if (err < 0)
  17.         goto out;
  18.     addr_len = err;

  19.     if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr &&
  20.      (err = unix_autobind(sock)) != 0)
  21.         goto out;

  22.     timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);

  23.     /* First of all allocate resources.
  24.      If we will make it after state is locked,
  25.      we will have to recheck all again in any case.
  26.      */

  27.     err = -ENOMEM;

  28.     /* create new sock for complete connection */
  29.     newsk = unix_create1(sock_net(sk), NULL);
  30.     if (newsk == NULL)
  31.         goto out;

  32.     /* Allocate skb for sending to listening sock */
  33.     skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);
  34.     if (skb == NULL)
  35.         goto out;

  36. restart:
  37.     /* Find listening sock. */
  38.     other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err); // 查找对端sock
  39.     if (!other)
  40.         goto out;

  41.     /* Latch state of peer */
  42.     unix_state_lock(other);

  43.     /* Apparently VFS overslept socket death. Retry. */
  44.     if (sock_flag(other, SOCK_DEAD)) {
  45.         unix_state_unlock(other);
  46.         sock_put(other);
  47.         goto restart;
  48.     }

  49.     err = -ECONNREFUSED;
  50.     if (other->sk_state != TCP_LISTEN) // 必须是监听状态
  51.         goto out_unlock;
  52.     if (other->sk_shutdown & RCV_SHUTDOWN) // 没关闭接收端
  53.         goto out_unlock;

  54.     if (unix_recvq_full(other)) {    //接收队列满了怎么办
  55.         err = -EAGAIN;
  56.         if (!timeo)
  57.             goto out_unlock;

  58.         timeo = unix_wait_for_peer(other, timeo);

  59.         err = sock_intr_errno(timeo);
  60.         if (signal_pending(current))
  61.             goto out;
  62.         sock_put(other);
  63.         goto restart;
  64.     }

  65.     /* Latch our state.

  66.      It is tricky place. We need to grab our state lock and cannot
  67.      drop lock on peer. It is dangerous because deadlock is
  68.      possible. Connect to self case and simultaneous
  69.      attempt to connect are eliminated by checking socket
  70.      state. other is TCP_LISTEN, if sk is TCP_LISTEN we
  71.      check this before attempt to grab lock.

  72.      Well, and we have to recheck the state after socket locked.
  73.      */
  74.     st = sk->sk_state;

  75.     switch (st) {
  76.     case TCP_CLOSE: // 我们这边的状态也要正确
  77.         /* This is ok... continue with connect */
  78.         break;
  79.     case TCP_ESTABLISHED:
  80.         /* Socket is already connected */
  81.         err = -EISCONN;
  82.         goto out_unlock;
  83.     default:
  84.         err = -EINVAL;
  85.         goto out_unlock;
  86.     }

  87.     unix_state_lock_nested(sk);

  88.     if (sk->sk_state != st) {
  89.         unix_state_unlock(sk);
  90.         unix_state_unlock(other);
  91.         sock_put(other);
  92.         goto restart;
  93.     }

  94.     err = security_unix_stream_connect(sk, other, newsk);
  95.     if (err) {
  96.         unix_state_unlock(sk);
  97.         goto out_unlock;
  98.     }

  99.     /* The way is Fastly set all the necessary fields... */

  100.     sock_hold(sk);
  101.     unix_peer(newsk)    = sk;    //设置对端地址
  102.     newsk->sk_state        = TCP_ESTABLISHED;
  103.     newsk->sk_type        = sk->sk_type;
  104.     init_peercred(newsk);
  105.     newu = unix_sk(newsk);
  106.     RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
  107.     otheru = unix_sk(other);

  108.     /* copy address information from listening to new sock*/ //对端的监听地址就是服务器的地址
  109.     if (otheru->addr) {
  110.         atomic_inc(&otheru->addr->refcnt);
  111.         newu->addr = otheru->addr;
  112.     }
  113.     if (otheru->path.dentry) {
  114.         path_get(&otheru->path);
  115.         newu->path = otheru->path;
  116.     }

  117.     /* Set credentials */
  118.     copy_peercred(sk, other);

  119.     sock->state    = SS_CONNECTED;
  120.     sk->sk_state    = TCP_ESTABLISHED;
  121.     sock_hold(newsk);

  122.     smp_mb__after_atomic();    /* sock_hold() does an atomic_inc() */
  123.     unix_peer(sk)    = newsk;    // 设置对端地址

  124.     unix_state_unlock(sk);

  125.     /* take ten and and send info to listening sock */
  126.     spin_lock(&other->sk_receive_queue.lock);
  127.     __skb_queue_tail(&other->sk_receive_queue, skb);    //将生成的skb加入到对端的接收队列中
  128.     spin_unlock(&other->sk_receive_queue.lock);
  129.     unix_state_unlock(other);
  130.     other->sk_data_ready(other);    // 通知对端有数据接收
  131.     sock_put(other);
  132.     return 0;

  133. out_unlock:
  134.     if (other)
  135.         unix_state_unlock(other);

  136. out:
  137.     kfree_skb(skb);
  138.     if (newsk)
  139.         unix_release_sock(newsk, 0);
  140.     if (other)
  141.         sock_put(other);
  142.     return err;
  143. }

connect实现的功能就是构造一个空的skb,将它发送到服务器的接收队列中,并唤醒阻塞在accept状态的服务端
 sk->sk_data_ready    =    sock_def_readable;
当有数据可读时,内核调用sock_def_readable函数

点击(此处)折叠或打开

  1. static void sock_def_readable(struct sock *sk)
  2. {
  3.     struct socket_wq *wq;

  4.     rcu_read_lock();
  5.     wq = rcu_dereference(sk->sk_wq);
  6.     if (wq_has_sleeper(wq))    //sock 等待队列中有进程
  7.         wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLPRI |
  8.                         POLLRDNORM | POLLRDBAND); //唤醒等待队列上的进程
  9.     sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);    //通知异步队列上的进程
  10.     rcu_read_unlock();
  11. }




阅读(2315) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~