UNP卷一学习笔记:基本TCP套接字

Posted printfnothing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNP卷一学习笔记:基本TCP套接字相关的知识,希望对你有一定的参考价值。

今天看了UNP卷一中与TCP相关的基本套接字函数,在这里总结下:

1.socket函数

#include<sys/socket.h>
int socket(int family,int type,int protocol);
//成功返回非负描述符,出错返回-1. 
注意点:

(1)family指明协议族:

family说明
AF_INETIPV4协议
AF_INET6IPV6协议
AF_LOCALUnix域协议
AF_ROUTE路由套接字
AF_KEY密钥套接字








(2)type指明套接字类型:

type说明
SOCK_STREAM字节流套接字
SOCK_DGRAM数据报套接字
SOCK_SEQPACKET有序分组套接字
SOCK_RAW原始套接字











(3)protocol指明某个协议类型常值,或者设为0,并通过family和type组合选择系统默认值。

protocol
说明
IPPROTO_TCPTCP传输协议
IPPROTO_UDPUDP传输协议
IPPROTO_SCTPSCTP传输协议









2.connect函数

#include<sys/socket.h>
int connect(int sockfd,const struct sockaddr* servaddr,socklen_t addrlen);
//成功返回0,出错返回-1

注意点:

(1)connect函数一般作为TCP客户端函数,客户端在调用connect前不必调用bind函数,内核会自动确定IP地址,并选择一个临时端口作为源端口。

(2)作为TCP套接字函数被调用时,connect出错一般是以下3种情况:

①客户端没有收到SYN分节的响应,connect会返回ETIMEDOUT错误。

②客户端收到了SYN分节的响应,但是是RST分节,表明服务器主机在客户端指定的端口没有运行相应进程在等待与之连接。此时connect函数会返回ECONNREFUSED错误。

③客户端发送的SYN分节在中间某个路由器引发“destination unreachable”ICMP错误,则connect函数返回EHOSTUNREACH或者ENETUNREACH错误。

3.bind函数:

#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen);
//成功返回0,出错返回-1
注意点:

bind函数的参数IP地址和端口号都是可选的,可以选其一指定,也可以两者都指定,或者都不指定。

IP地址
端口
结果
通配地址
0
内核选择IP地址和端口
通配地址
非0
内核选择IP地址,进程指定端口
本地IP地址
0
进程指定IP地址,内核选择端口
本地IP地址
非0
进程指定IP地址和端口








4.listen函数:

#include<sys/socket.h>
int listen(int sockfd,int backlog);
//成功返回0,出错返回-1
注意点:

listen函数仅由TCP服务器调用,它做两件事:

(1)listen函数将一个未连接的套接字转换成一个被动套接字,它指示内核接受指向该套接字的连接请求。

(2)backlog参数规定了内核应该为相应套接字排队的最大连接个数。

排队指两个队列:未完成连接队列(服务器收到某个客户端的SYN分节并做出响应,服务器此时处于SYN_RCVD状态)和已完成连接队列(服务器与客户端完成三次握手,此时服务器处于ESTABLISHED状态)。

5.accept函数

#include<sys/socket.h>
int accept(int sockfd,struct sockaddr* cliaddr,socklen_t* addrlen);
//成功返回非负描述符,出错返回-1.
注意点:

如果accept成功,那么将返回一个内核自动生成的全新描述符,代表与所返回客户的TCP连接。我们将accept函数的第一个参数称为监听套接字,将返回的描述符称为已连接套接字。一个服务器通常仅创建一个监听套接字,它在服务器的生命期内一直存在;而当服务器完成对某个客户端服务时,相应的已连接套接字就被关闭。

6.fork函数

#include<unistd.h>
pid_t fork(void);
//在子进程中返回0,在父进程中返回子进程ID,出错返回-1.
注意点:

fork函数被调用一次,那么在父进程中返回一次,返回子进程ID;在子进程中返回一次,返回0。

fork的两种典型用法:

(1)一个进程创建一个自身的副本,这样每个副本可以在其他副本执行其他任务时,处理自己的操作。

(2)一个进程想要执行另一个新的程序。进程fork子进程后,再调用exec函数把自身替换成新程序,称调用exec函数的进程为调用进程。

7.exec函数

#include<unistd.h>
int execl(const char* pathname,const char*arg0,....(char*)0);
int execv(const char* pathname,char *const argv[]);
int execle(const char* pathname,const char* arg0,....(char*)0);
int execve(const char* pathname,char* const argv[],char* const envp[]);
int execlp(const char* filename,const char* arg0,....(char*)0);
int execvp(const char* filename,char* const argv[]);
//均返回:成功则不返回,出错返回-1.
注意点:

这些函数只在出错时才返回到调用者,否则,控制将被传递给新程序的起始点,通常是main函数。

这些函数的区别在于

(a)待执行的程序文件是由文件名(filename)还是由路径名(pathname)指定;

(b)新程序的参数是一一列出还是由一个指针数组来引用,若是一一列出,则必须以一个空指针作为最后一个参数;若是由一个指针数组,则该数组最后一个变量应该为空指针。

(c)把调用进程的环境传递给新程序还是给新程序指定新环境。

8.close函数

#include<unistd.h>
int close(int sockfd);
//成功返回0,出错返回-1
注意点:

close一个TCP套接字的默认行为是把该套接字标记成已关闭,然后立即返回到调用进程。被close的套接字描述符不能再由调用进程使用,不能再作为read和write的第一个参数。导致的后果是TCP可能无法发送完全部数据,要想改变这种默认行为可以通过修改套接字选项。

9.getsockname函数getpeername函数。

#include<sys/socket.h>
int getsockname(int sockfd,struct sockaddr* localaddr,socklen_t* addrlen);
int getpeername(int sockfd,struct sockaddr* peeraddr,socklen_t* addrlen);
//均返回:若成功则为0,出错则返回-1
以下情况会使用这两个函数:

(a)在一个没有调用bind的TCP客户端上,connect成功返回后,getsockname用于返回由内核赋予该连接的本地IP地址和端口号。

(b)在以端口号0调用bind时候,getsockname会返回内核赋予的本地端口号。

(c)getsockname可用于获取某个套接字的地址族。

(d)如果服务器绑定通配IP地址,则getsockname通过已连接套接字描述符,返回由内核赋予该连接的本地IP地址。

(e)当一个服务器是由调用过accept的某个进程通过调用exec执行程序时,它能够获取客户身份的唯一途径便是调用getpeername。




以上是关于UNP卷一学习笔记:基本TCP套接字的主要内容,如果未能解决你的问题,请参考以下文章

UNP卷一学习笔记:基本UDP套接字编程

UNP卷一学习笔记:TCP状态

UNP卷一学习笔记:TCP服务器常见故障

UNP卷一学习笔记:TCP服务器常见故障

UNP卷一学习笔记:I/O模型

UNP卷一学习笔记:I/O模型