1、目录1 课程设计简介41.1 课程设计的目的41.2 课程设计内容42课程设计实现过程52.1 协议原理52.2 客户机/服务器模式72.3 关键技术82.4 流程图102.5 系统结构图112.6 程序调试及界面效果图112.7 源代码153设计总结224参考文献23.20.1 课程设计简介1.1 课程设计的目的 开发一个专用于实现两台计算机之间即时通讯的软件,以方便两台或两台以上的计算机之间信息的交流。,在连接并通信时,尤其是近程的即时通讯,彻底的脱离了远程的服务器,避免了和远程服务器连接时过多的浪费网络资源。并且避免了服务器忙或与服务器无法连接时,浪费过多时间用于和服务器建立连接!因此,
2、这个软件是极具适应性和实用性的即时通讯软件!本次课程设计的目的是学习基于UDP协议实现网络聊天程序,已达到学会面向无连接方式的程序设计方法,并理解网络编程中面向无连接的概念。1.2 课程设计内容 1.实现一个基于UDP协议的简单的聊天程序,包括服务器和客户端。 2.支持多人聊天。 3.客户端具有图形化用户界面。 2课程设计实现过程2.1 协议原理 UDP协议的全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是
3、否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。 UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分别运行在同一台设备上的多个应用程序。 与所熟知的TCP(传输控制协议
4、)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。 UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。 UDP是无连接的,即发送数据之前不需要建立连接(当然发送数据结束时也没有连接可释放)因此减少了开销和发送数据之前的时延。 UDP使用的是尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。 UDP是面向报文的。发送方的UDP对应程序交下来的报文,在添加首部后就向下交付给IP
5、层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。 UDP是定义用来在互连网络环境中提供数据报交换的计算机通信的协议。此协议默认是IP下层协议。此协议提供了向另一用户程序发送信息的最简便的协议机制,不需要连接确认和保护复制,所以在软件实现上比较简单,需要的内存空间比起TCP相对较小。UDP包头由4个域组成,其中每个域各占用2个字节。 (1)源端口号(16位):UDP数据包的发送方使用的端口号。 (2)目标端口号(16位):UDP数据包的接收方使用的端口号。UDP协议使用端口号为不同的应用保留其各自的数据传输通道。UDP和rap协议正是采用这一机制,实现对同一时刻内多项
6、应用同时发送和接收数据的支持。 (3)数据报长度(16位)。数据报的长度是指包括报头和数据部分在内的总的字节数。理论上,包含报头在内的数据包的最大长度为65535字节。不过,一些实际应用往往会限制数据包的大小,有时会降低到8192字节。 (4)校验值(16位)。UDP协议使用包头中的校验值来保证数据的安全。(正文字体要求为宋体,字号为小四,行间距20磅,每段前空2字符)2.2 客户机/服务器模式 由于这次课程设计是实现点到点的可靠连接,所以在此使用UDP连接方式。在这个连接中,双方分为客户和服务器,他们各自的功能不同。客户机一方,UDP应用程序功能如下:(1) 打开通信信道(申请一套接字),并
7、连接到服务器在主机的保留端口,该端口对应服务器的UDP进程。(2) 向服务器发出请求报文,等待接收应答。(3) 从服务器方收到最终应答结果,或在不再请求时关闭信道并终止客户机进程。服务器一方,UDP应用程序动作如下:(1) 打开通信信道(申请一套接字),通知本地主机在某一保留端口接收客户机请求。(2) 等待客户请求到达指定端口。(3) 接收到请求,启动一新进程处理用户请求,同时释放旧进程以响应新的客户请求,一旦服务完成,关闭新进程与客户的通信链路。(4) 继续等待客户机请求。(5) 如果不想响应客户机请求,关闭服务器进程。2.3 关键技术Socket又称作套接字,它是使用标准Unix文件描述符
8、(filedescriptor)和其它程序通讯的方式。使用send()和recv()让你更好的控制数据传输。在Java 网络编程中,socket相当于应用程序的港口码头;在计算机网络中,套接字由ip地址和端口号组成,为进程之间通信提供地址。两个主机进行通信实际上就是两个主机中的应用进程互相通信,应用进程之间的通信又称为端到端的通信。为应用进程之间的通信提供运输服务的是运输层的运输协议,运输层需要有两种不同的运输协议,即面向连接的TCP和无连接的UDP。 在Java中,用于实现基于UDP的聊天程序,使用两个重要的类(DatagramSocket类和DatagramPacket类)。Datagra
9、mSocket类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。 在DatagramSocket上总是启用UDP广播发送。为了接收广播包,应该将 DatagramSocket绑定到通配符地址。在某些实现中,将DatagramSocket绑定到一个更加具体的地址时广播包也可以被接收。DatagramPacket类表示数据报包。 数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另
10、一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。服务程序工作在服务器的某个端口上,一旦启动服务,它将在这个端口上监听,等待客户程序发来请求,当有客户连接到该端口,accept()方法就返回一个Socket对象,可以用该对象获得一个输入输出流。服务器的套接字用服务器套接字类(ServerSocket)来建立。具体实现如下:(1)建立一个服务者,端口为6666。(2)服务者永远等待,一旦客户送来正确的请求,连接至该端口,accept()方法就返回一个Socket对象。(3)用返回的Socket对象创建数据输入流类的实例6666。用返回的Socket对象创建数据输出流
11、的实例8888。以上实例in和out是服务者用于从客户接受输入信息和向客户程序发送信息所用。此外,还需要用方法receive()和printIn()读取或输出一行数据。(4) 在客户端建立Socket对象,并进行异常处理,主机名和端口号与连接的服务器名和提供该服务的服务程序的监听端口必须一致。建立连接后用Socket类提供的Datagramsocket()和Datagrampacket()方法取得输入输出流。在服务器端,获得的输入流是客户端的输出流,而Socket获得的输出流是发向客户端的输入流,在客户端也是这样。获得socket的输入输出流之后,为了便于读写操作,需要在这两个流对象基础上建立
12、易于操作的数据流Datagramsocket, Datagrampacket。然后对输入输出流进行读写操作。在通信结束时关闭socket,以断开连接,释放资源。先关闭对应的输入输出流,再关闭socket本身。2.4 流程图 服务器端Socket建立流式套接字,返回套接字 Bind将套接字号宇本地地址相连 客户端Socket建立流式套接字,返回套接字waitforpackets检测并接受对方发来的消息waitforpackets接收来自客户的数据waitforpackets检测并接受对方发来的消息数据请求处理请求数据应答Button1_actionPerformed发送信息给对方Button1_
13、actionPerformed发送信息给对方Close关闭2.5 系统结构图Server服务器(192.168.1.77)ChatApp_01客户端(192.168.1.68)ChatApp_02客户端(192.168.1.78)ChatApp_03客户端(192.168.1.88)2.6 程序调试及界面效果图 2.6.1 调试前的准备 安装jdk1.6.0并在计算机的环境变量中配置好java环境。使用的实验环境是Windows XP,Eclipse 6.0,。使用3太主机进行通信,一台作为服务器,另外两台作为客户端。 2.6.2 程序调试过程启动eclipse首先在一台主机上运行服务器端程序
14、,再在另外两台机器上运行客户端程序。然后进入到用户的图形用户界面,输入客户端的IP,进行连接,如果连接成功,则客户端就可以通过与服务器端进行通信,然后服务器转发通信,实现了两个客户端之间的聊天功能。2.6.3 程序运行结果 服务器(192.168.1.77) ChatApp_01客户端(192.168.1.68) ChatApp_02客户端(192.168.1.78) ChatApp_03客户端(192.168.1.88)2.7 源代码 ChatFram.javapackage ChatFrame_01;import .*;import java.io.*;import java.awt.*;
15、import java.awt.event.*;import javax.swing.*;import java.lang.*;import java.awt.color.*;import javax.swing.JOptionPane;public class ChatFrame extends JFrame JPanel contentPane;JLabel label1 = new JLabel();/ 发送消息JLabel label2 = new JLabel();/ 输入ipLabel label3 = new Label();/ 输入端口标签Label label4 = new
16、Label();/ 输出端口标签JTextField textField1 = new JTextField();/ 发送消息JTextField textField2 = new JTextField();/ 输入ipJTextField textField3 = new JTextField();/ 获得输入端口JTextField textField4 = new JTextField();/ 获得输出端口JButton button1 = new JButton(发送);/ 发送消息TextArea textArea1 = new TextArea();JOptionPane jopa
17、ne = new JOptionPane();DatagramPacket sendpacket, receivepacket;/ 声明发送和接收数据包DatagramSocket sendsocket, receivesocket;/ 声明发送和接收DatagramSocketpublic ChatFrame() enableEvents(AWTEvent.WINDOW_EVENT_MASK);try toInit(); catch (Exception e) e.printStackTrace();private void toInit() throws Exception content
18、Pane = (JPanel) this.getContentPane();label1.setText(发送信息:);label1.setBounds(new Rectangle(13, 100, 60, 21);contentPane.setLayout(null);contentPane.setBackground(Color.pink);this.setSize(new Dimension(363, 502);this.setTitle(多人聊天室);label2.setText(输入对方IP地址:);label2.setBounds(new Rectangle(12, 19, 109
19、, 23);label3.setText(输入端口:);label3.setBounds(new Rectangle(12, 58, 55, 22);label4.setText(输出端口:);label4.setBounds(new Rectangle(180, 58, 55, 22);textField3.setText(3000);textField4.setText(3001);button1.setBounds(new Rectangle(280, 100, 59, 21);button1.addActionListener(new java.awt.event.ActionList
20、ener() public void actionPerformed(ActionEvent e) button1_actionPerformed(e););textField1.addKeyListener(new KeyAdapter() public void keyPressed(KeyEvent e) if (e.getKeyCode() = KeyEvent.VK_ENTER) String str = textField2.getText();String str1=textField1.getText();if (pareTo() != 0&!.equals(str1) try
21、 textArea1.append(nto + textField2.getText()+ : + 3000 + say: + textField1.getText();String s = textField1.getText();byte data = s.getBytes(UTF-8);sendpacket = new DatagramPacket(data,data.length,InetAddress.getByName(192.168.1.77),6666);sendsocket.send(sendpacket); catch (IOException exc) exc.print
22、StackTrace();textField1.setText(););textField4.setBounds(new Rectangle(240, 58, 90, 22);textField3.setBounds(new Rectangle(70, 58, 90, 22);textField2.setBounds(new Rectangle(123, 20, 120, 19);textField1.setBounds(new Rectangle(76, 100, 190, 19);textArea1.setBounds(new Rectangle(11, 140, 333, 315);te
23、xtArea1.setEditable(false);textArea1.setBackground(Color.white);contentPane.add(label4, null);contentPane.add(label3, null);contentPane.add(label2, null);contentPane.add(label1, null);contentPane.add(textField1, null);contentPane.add(textField2, null);contentPane.add(textField3, null);contentPane.ad
24、d(textField4, null);contentPane.add(textArea1, null);contentPane.add(button1, null);this.setVisible(true);bind();protected void processWindowEvent(WindowEvent e) super.processWindowEvent(e);if (e.getID() = WindowEvent.WINDOW_CLOSING) System.exit(0);public void waitforpackets() / 检测并接受对方发来的消息while (t
25、rue) try byte array = new byte100;receivepacket = new DatagramPacket(array, array.length);receivesocket.receive(receivepacket);/ 接收textArea1.append(nfrom + receivepacket.getAddress() + :+ receivepacket.getPort() + get:);String received = new String(receivepacket.getData(), 0,receivepacket.getLength(
26、), UTF-8);textArea1.append(received); catch (IOException se) se.printStackTrace();void bind() / 和对方建立连try sendsocket = new DatagramSocket(3000);receivesocket = new DatagramSocket(3333); catch (Exception e) void button1_actionPerformed(ActionEvent e) / 发送消息到对方String str = textField2.getText();String
27、str1=textField1.getText();if (pareTo() != 0&!.equals(str1) try textArea1.append(nto + textField2.getText() + : + 3000+ say: + textField1.getText();String s = textField2.getText()+|+textField1.getText();byte data = s.getBytes(UTF-8);sendpacket = new DatagramPacket(data, data.length, InetAddress.getBy
28、Name(192.168.1.77), 6666);sendsocket.send(sendpacket); catch (IOException exc) exc.printStackTrace();textField1.setText(); ChatApp.javapackage ChatFrame_01;import java.io.*;import javax.swing.UIManager;import java.awt.*;public class ChatApp boolean packFrame = false;ChatApp() ChatFrame frame = new C
29、hatFrame();if (packFrame) frame.pack(); else frame.validate();/ 放置窗体在屏幕中央Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();Dimension frameSize = frame.getSize();if (frameSize.height screenSize.height) frameSize.height = screenSize.height;if (frameSize.width screenSize.width) frameSi
30、ze.width = screenSize.width;frame.setLocation(screenSize.width - frameSize.width) / 2,(screenSize.height - frameSize.height) / 2);frame.setVisible(true);frame.waitforpackets();public static void main(String args) new ChatApp(); Server.javapackage ChatFrame_01;import .DatagramPacket;import .DatagramS
31、ocket;import .InetAddress;import .Socket;import java.util.*;public class Server List ips = new ArrayList();DatagramSocket socket;DatagramPacket packet;DatagramSocket ssocket;DatagramPacket spacket;public Server() throws Exception socket = new DatagramSocket(6666);ssocket=new DatagramSocket(8888);pub
32、lic void listen() throws Exception byte array = new byte100;packet = new DatagramPacket(array, array.length);socket.receive(packet);byte data=packet.getData();String received = new String(data,0,data.length,UTF-8);System.out.println(received);String ss = received.split(|);String ip = ss0;byte dt=ss1
33、.getBytes(UTF-8);spacket=new DatagramPacket(dt,dt.length,InetAddress.getByName(ip),3333);ssocket.send(spacket);public static void main(String args) throws Exception Server s = new Server();while (true) s.listen();3设计总结这次课设我们是四个人一起完成的,在设计过程中,由于我们对java知识的掌握不够,因此参考了很多课外的相关书籍,并且在很多同学的帮忙下共同完成的。通过实践让我们进一步
34、掌握了网络和Java的结合,实现了网络编程。充分了解了基于UDP编程和功能模块化的优越性,这样便于维护和修改,并且很容易找到它有可能出现的错误和漏洞。当编译没有错误的时候,进行执行时,往往开始几次都不能达到自己的理想效果,这个时候的修改工作往往更加复杂,尤其是这个程序,整个程序大体上由几个类来控制,但是其实里面的类与类相互之间的联系很多,类与类相互之间相互交织在一起,在设计的时候我就考虑了把实现一些功能类似的按钮的事件响应放到一起,这样在编译出错时就能很容易的修改错误,看起来也清晰明了,所以功能模块化对程序的阅读、调试、修改起了很重要的作用。但是这个程序从整体上的设计就导致了程序本身很难把各个
35、功能模块化,这也是程序的一个BUG,如果改进的化要从开始设计的时候几个大类要重新规划。在设计程序的时候还要考虑到用户的非法操作而可能引起的系统错误和数据丢失,该程序在这方面做的不好,编程过程中没有充分考虑了各种可能出错的情况,纠错功能并不完善。改进的时候要把纠错功能充分的考虑进去。其实编写程序不仅仅让我们学到和更进一步的理解了语言算法的结构和思想,还进一步培养了我们缜密的思维,考虑问题更加周到。总之,要想学好更好,我们仍需培养更好的默契和付出更多的努力。 总的来说,这次设计的基于UDP协议的网络聊天程序还是比较成功的,在设计中遇到了很多问题,最后在老师的辛勤指导下,终于迎刃而解,有点小小的成就
36、感,终于觉得平时所学的知识有了实用的价值,达到了理论与实际相结合的目的,不仅学到了不少知识,而且锻炼了自己的能力,使自己对以后的路有了更加清楚的认识,同时,对未来有了更多的信心。最后,对给过我帮助的所有同学和各位指导老师再次表示忠心的感谢!4参考文献1 袁庆龙,候文义Ni-P合金镀层组织形貌及显微硬度研究太原理工大学学报,2001,32(1):51-53.(连续出版物:序号 主要责任者文献题名J刊名,出版年份,卷号(期号):起止页码)2刘国钧,王连成图书馆史研究北京:高等教育出版社,1979:15-18,31(专著:序号 主要责任者文献题名出版地:出版者,出版年:起止页码)3 孙品一高校学报编辑工作现代化特征中国高等学校自然科学学报研究会科技编辑学论文集(2)北京:北京师范大学出版社,1998:10-22(论文集:序号 主要责任者文献题名主编论文集名出版地:出版者,出版年:起止页码)