聊天程序 udp

分享于 

15分钟阅读

Web开发

  繁體 雙語

介绍

这个项目制作一个与局域网系统协作的聊天项目。 一般聊天程序使用面向连接的协议,这些程序需要客户端,至少一个服务器。 在公司中,如果需要聊天程序,服务器可以在这个服务器上运行,但是一般不需要服务器。

我在程序中尝试为这个小公司制作一个P2P聊天程序,homeusers没有任何服务器机器。 为了制作这个连接,我使用了 UDP ( 单位数据包) 协议广播系统。多线程体系结构。多态性。MDI ( Multiple-Document-Interface )。

我使用 C# 编程语言和 3.5. NET 框架。c#提供了增强的面向对象编程功能。

使用代码

多线程处理

C# 包含许多创新特性,其中最令人兴奋的是它内置的多线程编程支持。

多线程程序包含两个或者多个可以并发运行的部分。 此类程序的每个部分都称为线程,每个线程定义一个单独的执行路径。 因此,多线程是一种特殊的多任务形式。

多线程应用程序提供了一种错觉,即许多活动在或多或少地发生。 但是现实是CPU使用称为"时间片"的东西在不同线程之间进行 switch。

当程序创建一个 线程,程序指定线程 ThreadStart 将委托作为参数传递给 线程构造函数 ThreadStart 委托必须是一个方法返回 无效,不接受任何参数。

= new Thread(new ThreadStart(SendIHere));

在这里构造函数的线程 NAME 中 KeepAlive 及其委托 返回void的SendIHere 方法。 这个线程发送局域网"我仍然在线,不要在你的名单上告诉我"中的所有计算机。

在这种状态下 这里状态称为 准备就绪,或者 运行状态to呼叫开始。 在你调用start开始工作working开始工作直到你 睡眠 中止呼叫呼叫。

KeepAlive.Start();//开始线程直到睡眠或者终止呼叫失败。

线程可以通过调用 Sleep() 挂起自身。 以毫秒为单位接受参数。 我们可以使用特殊的超时 0来终止当前时间片,并给其他线程一个使用CPU时间的机会。

Thread.Sleep(60000);//this 表示等待 60000毫秒后再次工作。

有五个不同的线程在我的程序中运行。 因为没有使用相同的变量,所以我不满足任何使用这些线程。 对于使用相同变量的不同线程 C# 也提供监视类。

线程 threadudp:

这个线程在m 工作。 这里线程总是有效的,它的工作是来自网络的数据包。 这里线程监听 5000th 端口。 接收到任何数据包时。 这里线程发送 WaitForPackets 函数到构造函数。

线程 deleteactiviy:

这里线程在 这里线程休眠时间 60000 ms.This 线程删除未发送任何消息的用户活动 60000毫秒,使活动变为零。 如果用户的活动不是零,则首先检查它的活动,使它的为零。 如果是的话,那么就把它们从onlineuserlist中 delete。 这里线程发送 DeleteActvity 函数到构造函数。

线程 KeepAlive:

mainwindow.cs gile中的线程。 这个线程提供与P2P的通信。 广播"我在线"消息由这里线程发送。 这里线程休眠时间 10000毫秒。

lampard时间戳理论的消息编号。

线程 checkOnline:

这里线程在 mainwindow.cs 文件中也同样。 这个线程工作每 30000 milisecond. It的作业清理在线用户列表框和重写 List。 另外当收到新的用户消息时,还有另一个函数被称为 online() 编写他的NAME 列表框。

多个文档 InterFace(MDI):

多个文档界面程序允许用户编辑文档( 例如 PaintShop,AdopePhotoShop )。 一个MDI程序的应用程序窗口称为 父窗口。我的程序MDI父窗口是 windowmain.cs 窗体。 尽管MDI应用程序可以有许多子应用程序。 Publicroom和privateroom窗体是mainwindow的子。 而且,一次最多可以有一个子窗口处于活动状态。 子 Windows 不能在父级的外部。

对于创建 MDI,设置窗体属性的f IsMDIContainer为 true。

this.IsMdiContainer = true;

my窗体is窗体是父 MDI,publicroom和privateroom窗体是子窗体。

mainwindow窗体,用户face一个文本框,希望用户输入他们的NAME。 如果用户输入它的NAME,则publicroom窗体启动。 下面给出的代码显示publicroom如何启动。

publicroom = 新的PublicRoom(localusername);//构造publicroom发送 localusername

publicroom.MdiParent = this;//publicroom窗体是这里( 窗体窗体) 控件的子级。

publicroom.WindowState = 父边框中的FormWindowState.Maximized ;//maximized 子窗体。

可以从2 开始Privateroom表单,这是通过希望用户从列表中选择一个名称,然后从列表中发送"po"标头消息来打开"po"头消息来启动的。

我们也可以从线程UDP中监听到1 端口,Privateroom也可以在其他线程中调用这个线程,这会导致警告,这会导致警告。

同步

tcp/ip ( 面向连接) 检查连接。消息顺序以及消息是否到达或者是否到达。 如果使用 tcp/ip,我们不需要检查消息是否到达或者是否在线。

程序中最困难的部分是同步。 消息与用户同步同步。 因为UDP是无连接的单向协议

我为每个消息添加标题部分,也为丢失的消息添加Lamport时间戳。 在 Leslie Lamport的基础上,通过简单的机制创建了Lamport时间戳,该机制可以在numerically排序之前捕获 一个Lamport逻辑时钟是一个单调递增的软件计数器。

它遵循一些简单的规则:

  • 在每个事件发出前,计数器都会增加;
  • 当进程发送消息时,它包含带有消息的计数器值;
  • 接收消息时,进程将计数器作为它们自身值和接收值之间的最大值,然后在收到事件之前应用规则 1.( 2 )。

我在项目中使用Lamport时间戳,每个消息都有自己的消息编号。 如果缺少收件人,receiver希望发送方再次发送邮件。 如果它的顺序是 true,那么在屏幕上写。 当程序开始使用 100初始消息时。因为我将此值转换为字符串,所以从这个消息中得到三个字符,以便目标计算机容易地分离消息,并检查最后到达的消息编号。 如果丢失了消息,目标计算机将发送最后一个到达的邮件号码并希望丢失消息。 在每一个消息类型中我。

为了更新在线用户列表我创建了一个线程,这个线程发送我在这里每 20000毫秒( 计算机时钟时间)。 另外,线程发送我这里的消息,其中包含最后一个消息号和 private 房间号。 每个 private 房间使用不同的端口号。 若要阻止重合增加端口号。 用户的private 号码用于打开 private 房间。每个 private 房间连接都有不同的端口号,每个用户必须知道最后一个端口号,并在 public 房间设置端口号,以便下一个打开的房间设置端口号。

消息类型

我将消息类型与消息的第一个字符进行了。

"S"消息

这里消息显示用户是否处于联机状态。 在第二部分"s"消息类型存储用户的最后一个消息号。 第三部分是发送方使用的最大。 第四部分存储用户 NAME。 SendIHere,它由 KeepAlive 线程,函数每 10000毫秒发送这里消息。

示例:

S10514ahmet

如果我没有在你的List 添加我,如果我已经在你的List 变更我的活动参数,我发送服务消息。

"105"意味着我发送 5邮件检查与你从我收到的最后一条消息。

ahmet"是我的名字。

14表示publicroom中的最大 private 数,如果你 privateroomnumber 小于 14. 如果你想打开一个 private 房间,任何人都使用 15,并生成端口号 5015.

'M'消息:

这意味着你可以在屏幕上写这条消息。 这里消息类型还包括用户发送的消息的数量。

例如:

M108Hello

"M"消息头。

"108"发送 8消息。

Hello是我的消息。

'RA'消息:

返回 SendMessageBefore (。newuser,Convert.ToInt32(System.Text.Encoding.ASCII.GetString(data). 子字符串( 2,3 ) )。

获取服务消息或者消息,并获取用户最后一次收到的邮件的数目。

例如:

RA109

我有 9封邮件,但你发送的大于这个号码我错过了一些邮件再次发送。

'RR'消息

当某些消息丢失时用户发送"ra"头消息,并包括收到的最后一个消息号。

例如:

RR101hello

丢失的消息号,你没有获得第一个消息,这是"打招呼"。

"订单"消息:

这条消息意味着我想跟你聊天,打开你的房间。

"E"消息:

这里消息意味着我在你的List 中关闭了我的程序 delete。

从联机列表中删除用户:

从 List 中删除某人有两种方法。 从 List 中删除用户有两种条件。 如果两个值为零,则可以删除用户。 这些是用户类中的活动和被动值 Deleteactivity 线程每 60000毫秒工作一次。 这里线程使活动值为零。 如果消息出现,则该值为 1. 如果被动值为零,则活动已经为零。 在这里过程中,用户 array 和 DeleteUser Permanently() 函数将为空部分分配最后一个值,该函数将在这个空部分中指定最后一个值。 DeleteUserPermanently() 函数还减少了用户计数器并调整了 array的大小。

用户也可以通过从用户处获取E 类型邮件来删除。 有时可能出现运行时错误。 在这里情况下,用户程序 closes.When 用户程序关闭,发送这里消息或者数据包可能在 network.For 中丢失,这里情况同步会由第一个路径提供。

类:

Mainwindow.cs:

这是当程序类 starts.It 具有 MDI property.Its childforms时的第一个类 privateroom 表单和 publicroom 表单。

Mainwindow类提供程序工作的主要功能,它控制其他窗体。 开放UDP端口和等待包的进程也是类的其他作业。 它有输入按钮。用于用户名的文本框和文本框的警告标签。 而且它有Statustoolstrips控制器。

在 form.Threads 中有三个不同的线程开始使用标记。 用户签名后,用户可以通过在文件菜单中的签出退出程序。 退出进程后应用线程中止进程。 通过在AbortException中捕获中断进程来编辑进程,因为如果线程休眠模式中止无法处理。 ( 附录D )

主表单对到达数据包状态的进程进行处理。 它使用类函数在屏幕上写消息。 但是,由于 private 房间有自己的udp连接,它只发送,。NAME。端口号和 sstring NAME,用户打开 privateroom。

注:在附录部分给出类图。

Publicroom

Publicroom作为mainwindow窗体的子级,并且它的impossibe比mainwindow的大小大。 Textbox1,textbox2,listbox1,一个发送按钮和privateroom按钮是publicroom的内容。

on是mesages编写的文本框,并且on是一个文本框,在 listbox1.Send 按钮上显示 on.Online 用户的消息。 它还提供了消息,清理后的textbox1被写在 textbox2. private 按钮使所选人员连接 privateroom。

Publicroom在屏幕上写入从mainwindow发送的消息。 它发送的消息,上面写的,首先通过发送按钮对类进行分类。 Mainwindow类broadcoasts这些即将出现的消息。

要将消息从publicroom发送到mainwindow类,NotifyEventArgs。NotifyDaddyArgs。NotifyEnterArgs类被使用。

单击发送按钮时将生成 NotifyDaddyArgs。 这里类发送Textbox1消息。 这个类的形成导致了窗口中其他事件的执行。 ( 附录C )

UserOnlinePanel

Useronlinepanel是constracted的。 Useronlinepanel通过指定一个 array 变量来使用用户类。 这个类使我们获得关于用户的信息,并帮助同步 part.This 类主要控制这些'邮件是否属于新的门户网站或者名单上的某人','是消息号相同'?

用户

用户类是存储所有联机用户信息的类。 Useripendpoint存储上次发送的消息编号,nick NAME 和活动状态。 它由Onlineuserarray调用,它是useronlinepanel类中的一个 array 变量。 它使用 Ipendpoint。NAME 和整数值作为构造值。 用户的Ip和端口值。 NAME 是用户的昵称,它是字符串。 整数值是最后一次发送的消息数。

NotifyDaddyEventArgs类:

下面是 Windows 窗体. NET 应用程序中从一个窗体到另一个窗体的多种通信方式。 但是,当使用 MDI ( 多个文档界面) 模式时,可能会更好地将简单的事件连接到它的父容器窗体。

这里类在publicroom中单击发送按钮时形成。 构造函数将消息作为参数。 在这个类的构造之后,它在主窗口中被处理。

NotifyEnterEventArgs类:

当用户单击输入按钮时,这里类是发送消息所必需的。 它与NotifyDaddyEventArgs一样工作

Points of Interest

不需要服务器


CHAT  UDP  
相关文章