LINUX下的Socket网络编程TCP/IP

网络

学习过linux后了解到,在linux系统下的网络编程很有意思,在此,先要说一下TCP/IP,它是一个面向连接且可靠的一组协议,并且是全双工通信。它的存在使得网络世界缤纷多彩。linux内核将会提供一系列函数帮助我们完成网络编程。
想要对网络编程有认识,首先要知道其建立连接,数据传送,断开连接等过程。
我们知道目前从低向上公认有5层分别为:物理层,数据链路层,运输层,网络层,应用层。 这里主要讨论运输层即TCP层。

三次握手(三路握手)

我们知道,建立一个TCP连接需要经过三次握手的情形

  1. 服务器必须准备好接受外来的连接。这通常通过调用socket,bindlisten这三个函数来完成(下文会讲到这三个函数),这里称之为被动打开(passive open)。
  2. 客户通过调用connect发起主动打开(active open)。这导致客户TCP发送一个SYN分节,它告诉服务器客户将在(待建立的)连接中发送的数据的初始序列号。通常SYN分节不携带数据,其所在IP数据包只含有一个IP首部,一个TCP首部以及可能有的TCP选项。
  3. 服务器必须确定(ACK)客户的SYN,同时自己也得发送一个SYN分节它含有服务器将在同一连接中发送的数据的初始序列号。服务器在单个分节中发送SYN和对客户SYN的ACK(确认)。
  4. 客户必须确定服务器的SYN

这种交换至少需要3个分组,因此称之为TCP的三路握手。如下图
在这里插入图片描述

四次挥手

TCP的连接终止则需要4个分节

  1. 某个应用进程首先调用**close,**我们称该端执行主动关闭(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
  2. 接收到这个FIN的对端执行被动关闭(passive close)。这个FIN由TCP确认。它的接收也作为一个文件结束符( end-of-file)传递给接收端应用进程(放在已排队等候该应用进程接收的任何其他数据之后),因为FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
  3. 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
  4. 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
    既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。我们使用限定词“通常”是因为: 某些情形下步骤1的FIN随数据一起发送;另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节
    过程如下图
    在这里插入图片描述
    下图为一个完整的TCP连接所发生的实际分组交换情况,包含建立连接,数据交换,连接终止三个阶段。
    在这里插入图片描述

基本TCP套接字编程

这里主要采用C/S体系,即客户/服务器程序。想要执行网络的I/O,则一个进程必须做的第一件事就是调用socket函数,并且指定期望的协议类型(IPv4的TCP,IPv6的UDP,Unix域字节流协议等)。

一、服务端

1.socket函数

用来创建一个监听套接字,用来知道谁要连我
所在头文件:#include<sys/socket.h>
函数体:int socket(int family, int type, int protocol);

返回:成功则返回非负描述符,出错则为-1
其中family参数指明协议族,它通常是下述的某个常数值:
在这里插入图片描述
type参数指明套接字的类型,它通常是下属的某个值:

在这里插入图片描述
protocol参数则应当设为如下所示的某个协议类型的长治,或设置为0,从而以选择所给定的family和type组合系统所给的默认值。
在这里插入图片描述
socket函数在成功执行后会返回一个小的飞赴整数值,它与文件描述符类似,我们把它称之为套接字描述符,为了得到这个套接字描述符,我们只是指定来协议族和套接字类型,并没有指定本地协议地址或远程协议地址

2.bind函数

bind函数把一个本地协议地址赋予一个套接字
所在头文件:#include<sys/socket.h>
函数体:int bind(int sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
返回:成功则返回0,出错则为-1
上面socket函数返回的套接字描述符,其本质就是一个文件描述符,只不过不同的是他是一个指向网络的描述符,通过一系列指向最终指向了内核的struct sock结构体,如下图:
在这里插入图片描述
既然套接字已经创建好了,接下来就是想要让别人连接我,那么我必须公开我的IP地址以及端口号,那么bind函数就起到了这样的作用,它用来绑定一个IP地址和端口,便于别人来连接我们。
第一个参数:sockfd就是socket函数成功返回的监听套接字的值。
第二个参数:指向struct sockaddr结构体的一个指针struct sockaddr是一个通用结构体,因为内核并不知道我要绑定的是的IPv4的还是IPv6的甚至是绑定别的东西,因此这里设计一个通用的结构体,便于编程者去决定要绑定的东西。例如IPv4的结构体如下

struct sockaddr_in{
   
	sa_family_t sin_family;/*地址族:AF_INET*/
	u_int16_t sin_port;/*按网络字节序的端口*/
	struct in_addr sin_addr;/*internet地址,即IP地址*/
}
/*internet地址*/
struct in_addr{
   
	u_int32_t s_addr/*按网络字节序的地址*/
}

第三个参数:addrlen 则是第二个参数的大小。
这里值得一提的是,既然通过网络传输数据,那如果两方的机器的字节序不一样那么传输的数据是不能用的,因此规定网络上传输数据都要用网络字节序,这里系统已经提供好了一套字节序转换的函数:

#include 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值