基本TCP套接字编程
4.2 socket 函数
// 创建套接字文件描述符
#include <socket/socket.h>
//返回:若成功则返回非负描述符,出错则为-1
int socket(int family, int type, int protocol);
//example : socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
4.3 connect 函数
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
TCP套接字
1. 调用connect会激发TCP的“三次握手”
2. 若TCP客户没有收到SYN分节的响应, 返回ETIMEDOUT错误。
3. 客户发送SYN分节后,收到RST响应,表明在指定的端口上没有进程在等待与之连接, 返回ECONNREFUSES错误。
4. 若客户发送的SYN在中间某个路由器上引起了一个"destination unreachable"ICMP错误. 返回EHOSTUNREACH 或 ENETUNTREACH错误
5.调用connect失败后,都必须调用close函数关闭当前的套接字,如要再次调用connect函数,必须先重新调用socket函数
产生RST的三个条件:
目的地为某端口的SYN到达,然而该端口上没有正在监听的服务器;
TCP想取消一个已有连接;
TCP接收到一个根本不存在的连接上的分节。
4.4 bind 函数
int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); // 成功返回0,出错返回-1
//IPv4 通配地址
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
//IPv6 通配地址
struct sockaddr_in6 servaddr6;
servaddr.sin6_addr= in6addr_any;
进程绑定非通配IP地址到套接字上的常见例子是为多个组织提供web服务器的主机上(unp/v3/P83 挺有意思)
bind函数返回的常见错误是EADDRINUSE:地址已经被使用
4.5 listen 函数
int listen (int sockfd, int backlog)
//成功:返回0,出错则返回-1
backlog: 内核应该为相应套接字排队的最大连接个数
内核为每个监听的套接字维护两个队列
:
未完成连接队列:
由某个客户端发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程,这些套接字处于SYN_RCD状态
已完成连接队列:
每个已完成三次握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态。
未完成连接队列的个数+已完成连接队列的个数不超过backlog
4.10 getpeername 和 getsockname
getsockname返回与某个套接字关联的本地协议地址,getpeername返回与某个套接字关联的外地协议地址。
struct sockaddr_in cltaddr;
socklen_t len = sizeof (cltaddr);
if (getsockname(sockfd, (struct sockaddr*)(&cltaddr), &len) < 0){
err_sys("getsockname err.");
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。