TCP编程模型(TCP/IP网络编程)【linux】(zzs)


使用TCP通信时,TCP协议要求必须要有一个服务器端
这一点是由TCP协议本身的特性决定的,只要你使用TCP协议来通信,就必须要有一个TCP服务器端。

TCP服务器的大概工作过程

(1)服务器会使用专门“文件描述符”来监听客户的“三次握手”,然后建立连接。
(2)一旦连接建立成功,服务器会分配一个专门的“通信文件描述符”,用于实现与该连接客户的通信

由于建立连接时,双方的TCP协议都已经记住了对方IP和端口,所以双方正式通信时,TCP会自动使用记录的IP和端口,我们不需要重新指定对方的IP和端口。

TCP编程模型

想要实现TCP通信,怎么编程实现代码

在编程模型里面,必须要有一方是TCP服务器,另一方是TCP客户。

服务器只有一个,但是客户端有很多,不管客户端有多少个,一个服务器同时为多个客户端服务,客户端与服务器端的通信,都按照编程模型的描述来实现的。

图解说明:
TCP编程模型

上面编程模型图中,图解种只画了一个客户端,但是一个客户端,代表多个客户端,服务器端只有一个。

服务器端

服务器端创建套接字文件

调用socket函数创建套接字文件,返回套接字文件描述符,套接字文件描述符专门用于监听客户连接。

服务器端绑定

将套接字文件,服务器IP,服务器端口绑定在一起,端口指的是服务器程序的端口号。绑定在一起的目的就是建立固定对应关系,及就是套接字文件使用固定的IP,使用固定的端口。客户端主动向服务器端发起连接请求,所以服务器的IP和端口一定是固定的,而且是公开的。如果不固定,不公开,客户端就无法主动发起连接请求。

通过bind函数的参数来指定套接字文件描述符,服务器IP,服务器端口号。

服务器端创建被动文件描述符

调用socket函数创建套接字文件,返回套的接字文件描述符是一个主动文件描述符,主动文件描述符不能用来监听客户连接。
建立客户端与服务器端连接时,是由客户端主动向服务器发起请求,服务器是一个被动的过程,调用listen函数,将套接字文件描述符变为被动描述符,只有被动的文件描述符才能被动监听客户连接。

服务器端被动监听

被动监听客户的握手请求,被动监听及就是等,完成三次握手即连接成功,如果没有客户链接,上面accept函数是阻塞的,一旦有客户连接将不再阻塞,连接成功后,返回一个通信文件描述符。
通信文件描述符专门用来实现服务器端与其中一个刚建立连接的客户端之间的通信。

服务器端发送数据

接下来,服务器就可以使用accept函数返回的通信文件描述符向服务器端发送数据,发送数据时可以调用write函数,也可以调用send函数。调用这两个函数的时候,只需要指定通信文件描述符,不需要指定IP和端口,因为在建立连接的时候,服务器已经通过TCP自动记录了客户端的IP和端口。我们只需要使用文件描述符就会自动使用对应的客户端IP和端口。

服务器端接收数据

从调用read函数和recv函数从客户端使用通信文件描述符接收数据。

服务器端与客户端断开

当服务器端与服务器不需要通信的时候,需要进行四次挥手断开连接,四次挥手可由任意一方发起,服务器端主动断开连接,调用close(fd)或shutdown(fd)函数与某一个通信的客户端断开连接。服务器这里使用的fd是通信文件描述符,不是监听文件描述符。服务器端使用
通信文件描述符,断开的是通信文件描述符与哪一个客户端进行通信,那么就断开与对应客户端的连接。

断开的过程中,服务器端的TCP主动向客户端的TCP发起断开连接的请求,断开连接时会四次挥手。四次挥手成功,断开连接。

上面的编写步骤是由TCP协议来决定,使用TCP协议进行通信就必须使用TCP编程模型来编写服务器,否则无法使用TCP通信。

客户端

客户端创建套接字文件

调用socket函数返回skfd,创建套接字文件,返回套接字文件描述符。

客户端发起连接

调用connect(skfd……)函数,connet函数参数还需要写服务器的IP和端口,因为向服务器发起连接请求,必须要有服务器端的IP和端口,客户端才能知道向谁发起连接,主动向对应IP和端口的服务器发起握手请求,发起握手请求成功之后,客户端TCP会自动记录服务器端IP和端口。服务器端accept接受握手请求,也就是说客户端connect函数对应的是服务器端的accept函数。三次握手由双方TCP自动完成。三次握手OK,即连接成功,就可以正式进行通信。

客户端发送数据

客户端调用write函数和send函数向服务器端发送数据,服务器端通过read和recv函数接受数据。客户端发送数据的时候也不需要指定服务器端的IP和端口,在建立连接的时候已经自动记录了IP 和端口,所以只需要使用套接字文件描述符。客户端直接使用skfd来通信。

客户端接收数据

调用read(skfd)和recv(skfd)函数,接受服务器发送过来的数据,同样的参数只需要文件描述符即可接受服务器端发送过来的数据。

客户端断开连接

客户端断开连接,调用close(skfd)函数或者shutdown(skfd)函数即可断开连接。由客户端向服务器端主动发起断开连接的请求。调用函数之后,客户端TCP协议会主动向服务器端TCP协议发起断开连接的请求,四次挥手成功,断开连接。

服务器是如何同时应对多客户的通信呢?

多线程 和 多进程

图解说明:
多进程多线程实现服务器是如何同时应对多客户

服务器是主线程或者父进程,专门监听客户连接,请求连接并且连接成功,就返回一个专门用于通信的文件描述符,每当一个客户机连接成功,就创建一个次线程或者子进程,把用于通信的文件描述符给次线程或者子进程,次线程或者子进程拿到对用通信的文件描述符之后,就专门负责与对应的客户端进行通信。

以此类推,创建多个次线程或者子进程,来实现服务器端与多个客户端之间的通信。对于服务器来说,次线程和子进程是并发运行的。所以可以同时服务多个客户端。并且多个次线程和子进程不会干扰到主线程或者父进程的监听。因为主线程或者父进程与所有的次线程和子进程都是并发运行的,互不干扰。

多路io

主要使用seletc和poll机制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章