connect系统调用
当connect作用于流套接字的时候,是地址指明的对端建立连接,对于TCP来讲,connect会完成与对端的三次握手建立连接的过程;当connect作用于数据报套接字的时候,用于指明发送的对端地址,并且只能向该地址发送数据,指明之后,可以使用send等发送数据,无需使用sendto的参数再次指明发送地址;
/*
* Attempt to connect to a socket with the server address. The address
* is in user space so we verify it is OK and move it to kernel space.
*
* For 1003.1g we need to add clean support for a bind to AF_UNSPEC to
* break bindings
*
* NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and
* other SEQPACKET protocols that take time to connect() as it doesn't
* include the -EINPROGRESS status for such sockets.
*/ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
int, addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
int err, fput_needed; /* 找到socket */
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out; /* 地址复制到内核 */
err = move_addr_to_kernel(uservaddr, addrlen, &address);
if (err < )
goto out_put; /* 安全检查 */
err =
security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
if (err)
goto out_put; /* 调用对应类型的connect */
err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
sock->file->f_flags);
out_put:
fput_light(sock->file, fput_needed);
out:
return err;
}
这里主要看流式套接字的实现;
int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
int err; lock_sock(sock->sk);
err = __inet_stream_connect(sock, uaddr, addr_len, flags, );
release_sock(sock->sk);
return err;
}
建立连接过程中会根据socket的状态做不同的处理,连接并不一定马上完成,所以其也会有从连接中,到连接成功的状态转移;其中还包含了对阻塞socket和非阻塞socket的处理;tcp层的connect实现后续阅读过程中会进行补充;
/*
* Connect to a remote host. There is regrettably still a little
* TCP 'magic' in here.
*/
int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags, int is_sendmsg)
{
struct sock *sk = sock->sk;
int err;
long timeo; /*
* uaddr can be NULL and addr_len can be 0 if:
* sk is a TCP fastopen active socket and
* TCP_FASTOPEN_CONNECT sockopt is set and
* we already have a valid cookie for this socket.
* In this case, user can call write() after connect().
* write() will invoke tcp_sendmsg_fastopen() which calls
* __inet_stream_connect().
*/
/* 地址存在 */
if (uaddr) { /* 检查地址长度 */
if (addr_len < sizeof(uaddr->sa_family))
return -EINVAL; /* 对unspec的特殊处理 */
if (uaddr->sa_family == AF_UNSPEC) {
err = sk->sk_prot->disconnect(sk, flags);
sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
goto out;
}
} /* 根据socket状态对应处理 */
switch (sock->state) {
default:
err = -EINVAL;
goto out;
/* 已连接 */
case SS_CONNECTED:
err = -EISCONN;
goto out;
/* 正在连接 */
case SS_CONNECTING:
/* 对是否发消息做不同处理,fastopen*/
if (inet_sk(sk)->defer_connect)
err = is_sendmsg ? -EINPROGRESS : -EISCONN;
else
err = -EALREADY;
/* Fall out of switch with err, set for this state */
break;
/* 未连接 */
case SS_UNCONNECTED:
err = -EISCONN;
/* 需要为closed状态 */
if (sk->sk_state != TCP_CLOSE)
goto out; /* 传输层协议的connect */
err = sk->sk_prot->connect(sk, uaddr, addr_len);
if (err < )
goto out; /* 标记状态为正在连接 */
sock->state = SS_CONNECTING; /* fastopen */
if (!err && inet_sk(sk)->defer_connect)
goto out; /* Just entered SS_CONNECTING state; the only
* difference is that return value in non-blocking
* case is EINPROGRESS, rather than EALREADY.
*/
/* 非阻塞情况返回inprogress,阻塞返回already */
err = -EINPROGRESS;
break;
} /* 阻塞情况下需要获取超时时间,非阻塞为0 */
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); /* 已发送或者已收到syn */
if (( << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
int writebias = (sk->sk_protocol == IPPROTO_TCP) &&
tcp_sk(sk)->fastopen_req &&
tcp_sk(sk)->fastopen_req->data ? : ; /* Error code is set above */
/* 非阻塞退出,阻塞则等待连接,等待剩余时间为0,退出 */
if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))
goto out; /* 处理信号,达到最大调度时间或者被打断 */
err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out;
} /* Connection was closed by RST, timeout, ICMP error
* or another process disconnected us.
*/
/* 状态为关闭 */
if (sk->sk_state == TCP_CLOSE)
goto sock_error; /* sk->sk_err may be not zero now, if RECVERR was ordered by user
* and error was received after socket entered established state.
* Hence, it is handled normally after connect() return successfully.
*/ /* 设置为连接状态 */
sock->state = SS_CONNECTED;
err = ;
out:
return err; sock_error:
err = sock_error(sk) ? : -ECONNABORTED;
/* 设置未连接状态 */
sock->state = SS_UNCONNECTED;
if (sk->sk_prot->disconnect(sk, flags))
sock->state = SS_DISCONNECTING;
goto out;
}
对于阻塞socket,需要加入到等待队列中,等待连接完成;
/* 阻塞等待连接 */
static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
{
DEFINE_WAIT_FUNC(wait, woken_wake_function); /* 添加到等待队列 */
add_wait_queue(sk_sleep(sk), &wait);
sk->sk_write_pending += writebias; /* Basic assumption: if someone sets sk->sk_err, he _must_
* change state of the socket from TCP_SYN_*.
* Connect() does not allow to get error notifications
* without closing the socket.
*/
/* 等待连接状态改变 */
while (( << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
release_sock(sk);
timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
lock_sock(sk);
if (signal_pending(current) || !timeo)
break;
} /* 从等待队列移除 */
remove_wait_queue(sk_sleep(sk), &wait);
sk->sk_write_pending -= writebias;
return timeo;
}
connect系统调用的更多相关文章
- UDP socket也可以使用connect系统调用
UDP socket也可以使用connect系统调用 UDP是一个无连接的协议,因此socket函数connect()似乎对UDP是没有意义的,然而事实不是这样.它可以用来指定本地端口和本地地址,来建 ...
- Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()
前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...
- UDP中使用bind和connect的作用
1:UDP中可以使用connect系统调用 2:UDP中connect操作与TCP中connect操作有着本质区别. TCP中调用connect会引起三次握手,client与server建立连结.UD ...
- udp调用connect有什么作用(转)
原文链接如下: http://blog.csdn.net/wannew/article/details/18218619 整理一下.1:UDP中可以使用connect系统调用 2:UDP中connec ...
- UDP连接调用connect()函数
UDP是一个无连接的协议,它没有像TCP中EOF之类的东西. 8.11 UDP的connect函数 除非套接字已连接,否则异步错误是不会反悔到UDP套接字的. 我们确实能够给UDP套接字调用conne ...
- 从Linux源码看Socket(TCP)Client端的Connect
从Linux源码看Socket(TCP)Client端的Connect 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就来从Linux源码的 ...
- socket connect tcp_v4_connect
tcp_v4_connect /* This will initiate an outgoing connection. tcp_v4_connect函数初始化一个对外的连接请求,创建一个SYN包并发 ...
- Socket connect 等简要分析
connect 系统调用 分析 #include <sys/types.h> /* See NOTES */#include <sys/socket.h>int connect ...
- [转]C语言SOCKET编程指南
1.介绍 Socket编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措?等 ...
随机推荐
- 【HDU5469】Antonidas(点分治,字符串哈希)
[HDU5469]Antonidas(点分治,字符串哈希) 题面 HDU Vjudge 题解 啊哈?什么垃圾一眼点分治+Hash判断,哈哈哈哈哈,让我来码码码. 诶,怎么WA了.改改改改改. 诶,怎么 ...
- 【Learning】积性函数前缀和——洲阁筛(min_25写法)
问题描述 洲阁筛解决的问题主要是\(n\)范围较大的积性函数前缀和. 已知一积性函数\(f(i)\),求\(\sum_{i=1}^nf(i)\). \(n\leq10^{12}\). 求解方法 如 ...
- 洛谷 P1306 斐波那契公约数 解题报告
P1306 斐波那契公约数 题意:求\(Fibonacci\)数列第\(n\)项和第\(m\)项的最大公约数的最后8位. 数据范围:\(1<=n,m<=10^9\) 一些很有趣的性质 引理 ...
- 设置nginx日志滚动
需求:设置nginx每天凌晨12点轮转,系统版本为debian7,nginx版本为tengine2.2.0 1.修改logrotate主配置文件,打开压缩和以时间为后缀命名 # vim /etc/lo ...
- MVC中HTML控件设为只读readonly
http://www.th7.cn/web/html-css/201501/78934.shtml 1.下拉框设为只读试了试用这个有效: @Html.DropDownListFor(model =&g ...
- 使用 mysql-proxy 监听 mysql 查询
什么是 mysql-proxy? mysql-proxy是mysql官方提供的mysql中间件服务,上游可接入若干个mysql-client,后端可连接若干个mysql-server. 它使用mysq ...
- QCon技术干货:个推基于Docker和Kubernetes的微服务实践
2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...
- Xpath语法与lxml库的用法
BeautifulSoup 已经是非常强大的库了,不过还有一些比较流行的解析库,例如 lxml,使用的是 Xpath 语法,同样是效率比较高的解析方法. 1.安装 pip install lxml 2 ...
- timeshift 安装使用说明
https://blog.csdn.net/hunter___/article/details/79751379 这里介绍一个可视化的备份软件:Timeshift,它不只能备份你的个人文件夹或应用程序 ...
- Hadoop生态圈-注册并加载协处理器(coprocessor)的三种方式
Hadoop生态圈-注册并加载协处理器(coprocessor)的三种方式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 到目前为止,大家已经掌握了如何使用过滤器来减少服务器端通过 ...