Skip to content

Latest commit

 

History

History
63 lines (45 loc) · 4.36 KB

Day1.md

File metadata and controls

63 lines (45 loc) · 4.36 KB

文件说明

  • 文件创建时间:2020年04月09日
  • 最后修改时间:2020年04月09日
  • 文件主要内容:代码操作记录、实现的功能、问题分析及解决方案

操作日志

  • 实现的功能
  1. 客户端之间的群聊功能已经实现
  2. 客户端之间的私聊功能已经实现
  • 具体操作内容概述
  • 客户端
  1. 将握手函数拆分为数据发送函数和数据接受函数,提高函数复用率。
  2. 使用父子进程的方式实现了群聊功能,实现了避免产生孤儿进程的功能。
  3. 编写数据过滤函数,将私信数据的目标PID和私信消息过滤。
  • 服务器
  1. 服务器程序,编写私有管道名记录函数,将所有到来的客户端做记录。
  2. 编写服务器的数据发送函数,能够实现不将数据发给发来数据的客户端,此部分代码已被注释(觉得暂时没用)。实现了私发功能。

Bug集中营

一、群聊问题

  • 问题描述 刚刚遇到一个问题: 当第二个客户端连接进来之后,服务器就会依次向所有客户端发送相关信息。但是,此时第一个客户端正处在发送数据的情况下。也就是说,此时如果客户端1不能发送数据给服务器,那么此时服务器发给客户端1的信息就会被阻塞。这就导致其他所有客户端都不能接收到服务器的此条信息了。

  • 问题原因 该问题最根本的原因是,客户端的读写是顺序执行的,他只能写完数据之后才能有机会读数据。这就导致他写(公有管道)数据的时候,读(私有管道)被阻塞了。

  • 解决方案 如果要解决该问题,我觉得 必须 有必要采用父子进程的方式。这样就会解决读写顺序的问题。

PS: 本以为该问题很棘手,需要大量修改代码 😵
没想到,加上父子进程后,轻松解决 😜~~~

  • 需要注意的问题 在父子进程的程序中,需要注意避免产生孤儿进程和僵尸进程。本程序中,父进程用来向服务器写入数据,子进程用来从服务器读出数据。如果客户端想要退出程序,父进程首先向服务器发送CLIENT_QUIT消息,然后箱子进程发送SIGSTOP信号,终止子进程执行。这样可以避免子进程变为孤儿进程或僵尸进程。

下面附一张子进程变成孤儿进程的截图:

孤儿进程

二、私聊问题

  • 如何实现两个客户端的私聊? 若要实现客户端之间的私聊,可以在客户端发送的数据前加入报头,比如(to: [Client_PID] [Client_Message])。这样,就有两种处理方式:

    • 方式一、在客户端判断是否为私聊
      客户端自身判断一下前几个字符是否为固定报头。如果是的话,就截取目标PID和待发送的消息,同时用自己结构体中的成员标志记录下目标PID。服务器收到消息后,判断结构体的成员标记。如果是私聊,就单独发送;否则就向所有客户端循环广播发送数据。
    • 方式二、在服务器判断是否为私聊
      客户端加上包头之后,直接将所有数据发送至服务器。服务器接收到消息后,判断报头是否为私聊报头,进而作出相应处理。 为了减轻服务器的数据处理负担,我选择在客户端处理数据。
  • 关键问题 问题的关键在于如何正确地切分数据。看了看C语言的正则表达式。。。我还是自己写函数吧。这里的问题还是很多的,主要是一些细节问题。比如,进程的PID最多只有5位数,如果用户输入了错误的PID(长度超过5位数),如何进行位数限制;还有,假如用户没有严格按照规定格式输入,而是输入了一些无效的空格,怎样提高数据分割的容错性。等等问题。我写了个函数,实现了以下功能:

    • 能够按照规定格式正确切分客户端PID和客户端的有效消息
    • 能够忽略客户端所有无效的空格字符
    • 能够限制目标PID在5位数以内 客户端函数的目的,是能将私信目标PID和有效数据分隔开,只要能实现数据分割就可以了。至于判断目标PID是否有效,可以在服务器端实现。
  • 如何判断私信目标PID是否有效?(暂未实现) 现在的想法是,服务器读取私有管道文件,如果私有管道不存在,则拒绝通信。