基本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)

clipboard.png

clipboard.png

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;

clipboard.png

进程绑定非通配IP地址到套接字上的常见例子是为多个组织提供web服务器的主机上(unp/v3/P83 挺有意思)
bind函数返回的常见错误是EADDRINUSE:地址已经被使用

4.5 listen 函数

int listen (int sockfd, int backlog)
//成功:返回0,出错则返回-1

backlog: 内核应该为相应套接字排队的最大连接个数
内核为每个监听的套接字维护两个队列:

未完成连接队列:
由某个客户端发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程,这些套接字处于SYN_RCD状态
已完成连接队列:
每个已完成三次握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态。

未完成连接队列的个数+已完成连接队列的个数不超过backlog

clipboard.png

clipboard.png

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.");
}

shiyang6017
158 声望59 粉丝

引用和评论

0 条评论