基本TCP套接字编程
2015/07/24
1. connect()函数
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);//成功返回0,出错返回-1
1.1 出错情况
- TCP客户没有收到SYN分节响应(超时机制),返回
ETIMEDOUT
错误。 - 目标端口没有进程在等待连接,客户收到RST(复位)分节,返回
ECONNREFUSED
错误(硬错误)。RST分节产生的条件
- 端口上没有正在监听的服务器
- TCP想取消一个连接
- 收到一个不存在的连接的分节
- TCP客户发送的SYN分节在某路由上引发“不可达”(destination unreachable)ICMP错误(软错误)(超时机制),则返回
EHOSTUNREACH
或ENETUNREACH
错误。额外两种情况也触发该错误:本地系统转发表无到达远程系统的路径;connect()
不等待就返回。
1.2 注意
- connect函数导致socket由CLOSED状态转移到SYN_SENT状态,若成功,再转移到ESTABLISHED状态。
- connect失败后导致套接字不可再用,不能对该套接字再次调用
connect()
需要close()
。
2. bind()函数
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);//成功返回0,出错返回-1
给套接字一个地址(把IP地址捆绑到套接字上),套接字是主体,地址和端口是客体。
- 若未调用
bind()
就调用了connect()
或listen()
,内核就要为相应的套接字选择一个临时端口。 - 端口号为0则内核选择端口,IP地址为通配地址(
INADDR_ANY
),则内核选择IP地址。 - 常见错误:
EADDRINUSE
(地址已使用)
3. listen()函数
#include <sys/socket.h>
int listen(int sockfd, int backlog);//成功返回0,出错返回-1。
仅由TCP服务器调用,做两件事:
- 将
socket()
创建的主动套接字转为被动套接字,导致socket由CLOSED状态转移到LISTEN状态。 - 规定内核为相应套接字排队的最大连接数。
当客户SYN到达时,如果队列已满,TCP则忽略该分节,不发送RST,因为队满只是暂时的。
4. accept()函数
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)//成功返回非负描述符,出错返回-1。 由服务器调用,用于从已完成连接队列对头返回下一个已完成连接,如果已完成连接队列为空,那么进程被投入睡眠(阻塞)。
- 函数中的第一个参数 sockfd 为监听套接字,函数返回的是已连接套接字。
- 暂时不清楚 cliaddr (客户进程的协议地址)和 addrlen 与
getsockname()
或getpeername()
得到的地址的区别。
5. close()函数
#include <unistd.h>
int close(int sockfd);//成功返回0,出错返回-1。
通常的unix close函数,可以用来关闭套接字,终止TCP连接。
关闭过程如下图:
客户端或服务器都可以主动关闭。