计算机网络:聊天室(UDP)

一、预期结果

多个用户可以一起聊天,当用户加入/退出聊天室,聊天室每个成员都可以看到加入/退出用户的信息。

二、实现思路

(一)客户端

1.使用socket函数接口并且建立客户端地址信息

2.定义使用结构体和枚举,发送和接收直接用结构体。枚举用户状态(sigin、chat、quit),结构体(用户状态、用户昵称,用户消息)

3.用户加入时:向服务器发送登录状态

4.聊天过程:创建两个线程执行发送和接收服务器发送过来的消息。

5.退出时:通过发送线程,向服务器发送quit作为退出标志,

(二)服务器端

1.使用socket函数接口并且绑定服务器地址信息

2.定义同样的结构体来接收信息。因为服务器需要向每个在线的客户端发送结构体信息,所以需要保存加入的客户端地址信息。这里则还需要定义一个结构体来存放地址信息和用户的状态。

3.接收客户端发来的信息判断信息状态后执行操作。

①服务器接收的客户端状态为sigin:发送信息给每一个在线的客户端(可以将存在的客户端信息存在链表(数组)里面,然后遍历链表判断状态,发给每一个在线的客户端),将自己的地址尾插法插入链表(发送之后插入可以不用判断自己)。

②接收到的客户端信息为chat:发送消息给除自己之外的每一个客户端

③接收到的客户端信息为quit:发送给除自己每个用户之后,删除这个用户所在链表节点。

三、核心代码

四、成功展示

五、总结

在这个小项目实现的过程中,我遇到了两个问题并且最后解决了这两个问题。遇到困难对我来说是非常好的,因为我是在学习的过程,有问题解决它才能掌握正真的知识。

1.客户端与服务器传文件时,TCP中接收文件内容消息结束时为什么可以用recv的返回值==0来作为结束条件,而UDP却需要一个特殊的标志。

原因:TCP面向连接的特性,相当于建立了一个管道。服务器文件读完是发送端发送0,而接收端收到0会知道对面已经发送完毕了。

UDP无连接,发送文件,读完文件发送0时,接收端不知道它发送完毕。所以必须设置一个标志。

2.为什么在客户端定义的结构体全局变量msg,在主函数中输入msg.name,而在发送线程中msg.name没有被赋值。

原因:线程共享进程内存数据区,而定义的全局变量是他们俩共享的区域。如果recv接收到服务端发来的msg,则它们两个线程共享的msg会被更新。因此,需要定义一个全局变量用来存放主函数中输入的msg.name用来赋值给发送线程中给mag.name。又因为我在接收线程中recvfrom前加了bzero清除msg,所以导致发送是msg.name没有值。