Linux| |书写一个TCP服务器

TCP服务器


# 前序

TCP是有连接的,是面向字节流的,是可靠的

1. 对于TCP的理解

  • TCP是传输层协议,我们书写的TCP网络服务器是站在应用层写的调用的套接字API,也就是对于传输层封装的方法接口

  • 对于TCP是有连接的,所以首先要建立连接之后再次进行通信

  • 连接

    • 先描述在组织

    • 管理连接是要成本的

      • 空间和时间

2. TCP所使用的API

对于TCP所使用的API的UDP有相似之处。都具有socket函数,bind函数,需要用到地址转换函数,网络字节序转换函数等

但是对于TCP也有着自己的API

  • listen函数,accept函数,connect函数, recv函数,send函数

接下来就说一下这些函数的用法

2.1 listen函数

  • 函数原型

  • #include <sys/types.h>
    #include <sys/socket.h>
    ​
    int listen(int socked, int backlog);
    ​
    socked:文件描述符,表示使用那一个进行作为服务器进行监听
    backlog:(积压)挂起连接队列的最大长度,也就是可以最多有多少个客户端等待连接到服务器
    返回值:成功返回0,失败返回-1
  • 函数的作用

    • 该函数就是让sokced处于监听状态,并且backlag表明有多少个客户端可以处于连接等待状态

2.2 accept函数

  • 函数原型

  • #include <sys/socket.h>
    ​
    int accept(int socket, struct sockaddr* restrict address, 
               socklen_t *restrict address_len);
    ​
    socket:文件描述符,表明哪一个进程等待连接
    address:空指针或者sockaddr类型的结构指针,该结构用来存放客户端的sockaddr结构
    address_len:存放的是客户端的sockaddr结构的大小
  • 函数作用

    • 该函数适用于服务器

    • 该函数就是接受一个客户端连接

2.3 connect函数

  • 函数原型

  • #include <sys/socket.h>
    ​
    int connect(int socket, struct sockaddr* restrict address,
               socklen_t *restrict address_len);
    ​
    socket:文件描述符,表明哪一个进程要去连接
    address:空指针或者sockaddr类型的结构体指针,该结构体用来存放服务器的sockaddr结构
    address_t:存放的是服务器的sockaddr结构的大小
  • 函数作用

    • 该函数适用于客户端

    • 该函数就是让一个客户端连接到服务器端

2.4 recv函数

  • 函数原型

  • #include <sys/socket.h>
    ​
    ssize_t recv(int socket, void* buffer, size_t length, int flags);
    ​
    socket:文件描述符,表明哪个进程接收消息
    buffer:使用buffer来接收消息,buffer是存储消息的容器的地址
    length:该buffer是多大
    flags:接收消息的类型,默认是0
  • 函数作用

    • 该函数适用于客户端和服务器

    • 作用是接收一段消息

2.5 send函数

  • 函数原型

  • #include <sys/socket.h>
    ​
    ssize_t send(int socket, const void* buffer, size_t length, int flags);
    ​
    socket:文件描述符,表明哪个进程发送消息
    buffer:发送buffer里面的消息,buffer是存储消息的容器的地址
    length:该buffer是多大
    flags:发送的消息的类型,默认是0
  • 函数作用

    • 该函数适用于客户端和服务器

    • 作用是发送一段消息

3. TCP服务器的几种形式

对于多种版本形式,只是对于服务器进行修改,从而产生多种形式的服务器

 

3.1 单进程版本

  • 对于单进程版本是对于服务器只能和一个客户端进行连接

3.2 多进程版本

  • 可以和多个客户端进行连接

    • 每当一个客户端连接到来的时候,服务器就开辟一个子进程和这个客户端进行连接

    • 对于这个子进程一定要将其的SIGCHID的信号进行让主进程进行忽略

3.3 多线程版本

  • 可以和多个客户端进行连接

    • 每当一个客户端连接到来的时候,服务器的主线程就创建一个子线程和这个客户端进行连接

    • 对于这个子线程必须要将其进行分离,也即是不需要让主线程进行等待

3.4 线程池版本

  • 可以和多个客户端进行连接

    • 每当一个客户端连接到来的时候,就创建一个任务,将这个任务扔到任务池中,然后让这个线程池中的线程与客户端进行通信

# 对于TCP书写服务器的思路

由于TCP是有连接的,所以对于两个处于同一局域网下计算机的进程之间通信,所以是需要两台计算机之间的进程进行连接的。所以相比于UDP来说的话,TCP就多了监听,接受以及连接三个步骤

  • 服务器

    • 创建一个套接字

    • 将该套接字绑定到一个ip和端口

    • 然后使服务器的套接字处于监听状态

    • 该套接字等待接受一个连接请求

    • 连接请求到了之后,连接上了在进行接受消息和发送消息

    • 插图:服务器流程图

  • 客户端

    • 创建一个套接字

    • 然后就使用该套接字调用connect函数连接到服务器上

    • 连接成功之后,发送消息和接受消息

    • 插图:客户端流程图

# 对于TCP服务器要注意的问题

  • 服务器端

    • 通信的文件描述符发生了改变

      • 对于服务器采用accept函数接收一个客户端连接之后,accept函数返回一个新的文件描述符,之后就采用这个新的文件描述符来与客户端进行通信,而不需要刚开始的时候对于服务器绑定的那个文件描述符

    • 通信结束之后关闭文件描述符

      • 对于通信之后要关闭文件描述符,否则的话因为文件描述符的这个资源是有限的,所以使用完了文件描述符一定要进行关闭否则的话,会造成文件描述符的泄露

      • 就会导致服务器端无法再被客户端进行连接,因为已经没有文件描述符可被分配了

  • 客户端

    • 知道服务器的ip地址和端口号

      • 这是因为客户端要主动连接到服务器端上去,所以对于启动客户端的时候一定要把服务器端的ip地址和端口号传给客户端,这样的话两个计算机才可连接通信

接下来将使用TCP书写服务器的思路:

最后再附上自己书写的各种形式TCP服务器的代码:

 https://github.com/YKitty/LinuxDir/tree/master/LinuxCode/netWork/TCP

猜你喜欢

转载自blog.csdn.net/qq_40399012/article/details/86368899