Linux网络编程

TCP/IP四层模型

TCP/IP是一组用于实现网络互连的通信协议Internet网络体系结构以TCP/IP为核心。基于TCP/IP的参考模型将协议分成四个层次,它们分别是:网络访问层、网际互联层、传输层(主机到主机)、和应用层。
1. 应用层
应用层对应于OSI参考模型的高层,为用户提供所需要的各种服务,例如:FTP、Telnet、DNS、SMTP等.
2. 传输层
传输层对应于OSI参考模型的传输层,为应用层实体提供端到端的通信功能,保证了数据包的顺序传送及数据的完整性。该层定义了两个主要的协议:传输控制协议(TCP)和用户数据报协议(UDP).
TCP协议提供的是一种可靠的、通过“三次握手”来连接的数据传输服务;而UDP协议提供的则是不保证可靠的(并不是不可靠)、无连接的数据传输服务.
3. 网际互联层
网际互联层对应于OSI参考模型的网络层,主要解决主机到主机的通信问题。它所包含的协议设计数据包在整个网络上的逻辑传输。注重重新赋予主机一个IP地址来完成对主机的寻址,它还负责数据包在多种网络中的路由。该层有三个主要协议:网际协议(IP)、互联网组管理协议(IGMP)和互联网控制报文协议(ICMP)。
IP协议是网际互联层最重要的协议,它提供的是一个可靠、无连接的数据报传递服务。
4. 网络接入层(即主机-网络层)
网络接入层与OSI参考模型中的物理层和数据链路层相对应。它负责监视数据在主机和网络之间的交换。事实上,TCP/IP本身并未定义该层的协议,而由参与互连的各网络使用自己的物理层和数据链路层协议,然后与TCP/IP的网络接入层进行连接。地址解析协议(ARP)工作在此层,即OSI参考模型的数据链路层。

TCP与UDP的区别

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,完成第四层传输层所指定的功能。
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。

TCP与UDP基本区别:
1、基于连接与无连接。
2、TCP要求系统资源较多,UDP较少。
3、UDP程序结构较简单。
4、流模式(TCP)与数据报模式(UDP)。
5、TCP保证数据正确性,UDP可能丢包。
6、TCP保证数据顺序,UDP不保证。
7、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
8、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
9、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)。
10、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
11、TCP首部开销20字节;UDP的首部开销小,只有8个字节。
12、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

TCP建立连接的过程

三次握手

TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急) Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。 完成三次握手,主机A与主机B开始传送数据。

四次挥手

TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。

Socket(套接字)概念

socket又称“套接字”,是计算机网络中进程间通信数据通道的一个端点,或称之为句柄。IP地址+端口号就可以唯一确定一个socket。
TCP/IP协议族包括传输层(TCP/UDP),网络层(ICMP/IP/IGMP),链路层(ARP/RARP)。应用层通常使用socket地址,即IP地址+端口号来确定通信的对端。而socket正是TCP/IP协议族与应用层之间的接口层,可以说对上层提供了TCP/IP协议族的一种封装,无需关心更底层的实现。
应用上通常使用一些更高层的协议库来编程,socket更多归类于底层驱动编程。不过熟悉socket总归是有好处的。

套接字地址结构

IP地址+端口号可以唯一确定一个socket套接字地址,命名为sockaddr_in,位于netinet/in.h头文件中,定义如下。
struct in_addr{
in_addr_t s_addr;
};
struct sockaddr_in{
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero(0);
};
in_addr_t in_port_t位于netinet/in.h
in_addr_t一般定义为uint32_t,in_port_t一般定义为uint16_t
sa_family_t位于sys/socket.h
uint8_t等位于sys/types.h中
sin_addr sin_port即为以网络字节序存储的32位ip地址与端口号
套接字地址有很多种,为了能够统一以指针的形式使用socket API,使用时需要转换为通用套接字地址sockaddr,一般进行强制类型转换即可。

socket基本TCP API

socket函数

socket函数用以创建一个socket。
int socket(int family, int type, int protocal);
family通常设置为AF_INET`AF_INET6,分别表示IPv4/6协议。
type通常设置为SOCK_STREAM SOCK_DGRAM SOCK_RAW,分别表示字节流(TCP),数据报(UDP),原始套接字。
protocal表示协议族,IPPROTO_TCP'IPPROTO_UDP
通常设置为0也可。
返回值表示非负套接字描述符

connect函数

用于建立连接
int connect(int sockfd, const struct sockaddr *servaddr, int addrlen);
TCP客户端用connect函数与服务器端建立连接
此函数将激发TCP的三次握手连接过程,直到链接建立成功或出错才返回
每个socket只能调用一次connect,出错后必须close当前socket再次重新依次调用socket、connect
函数参数为socket描述符,通用socket地址指针及其结构体大小。

bind函数

bind将IP地址和端口绑定到套接字描述符
int bind(int sockfd, const struct sockadddr *myaddr, int addrlen);
如果sin_addr.s_addr设置为INADDR_ANY,且主机有多个网络接口,则可以在多个网络接口接受用户connect

listen函数

listem将一个未调用connect函数的socket转换为一个被动监听套接字
int listen(int sockfd, int backlog);
backlog规定了挂起连接的最大数量

accept函数

内核为任一个监听套接字维护一个正在处于握手连接阶段的未完成连接队列,以及已完成连接队列
accept每次接受一个监听套接字描述符,返回一个已连接队列中的已连接套接字描述符
已连接套接字的套接字地址与地址长度存放于cliaddr与addrlen指向的内存中。如果使用两个0来调用,则无法得到客户端已连接套接字表示的地址与端口等信息。
对于每个处理完毕的连接,应该close,否则可能耗尽套接字描述符
int accept(int sockfd, struct sockaddr *cliaddr, int *addrlen)

close函数

close一个TCP套接字默认行为是把socket标记为关闭后返回。但触发了四次挥手过程
int close(int sockfd);

传送数据

通常需要一个缓冲区,之后使用recv、send函数接收发送
read、write在*nix系统上也可以
int recv(int sockfd, void *buf, size_t len, int flags);
int send(int sockfd, const void *buf, size_t len, int flags);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值