基于CS的简单聊天程序2012211466宋余保

更新时间:2023-10-21 10:01:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

计算机网络课程设计任务书

学 院 课程名称 计算机与信息工程学院 计算机网络 专 业 物联网工程 题 目 基于C/S的简单聊天程序 完成期限 自2014年6月9日至2014年6月16日共1周 一、项目的目的 利用socket。实现客户与服务器间的信息互通。 二、项目任务的主要内容和要求 (1)首先,设计一个登录程序。验证通过后才能进入聊天室。 (2)用户聊天室具有群发,私聊,输入昵称与端口号等基本设置。 点击“连接”按钮实现与服务器的连接。点击“断开”按钮实现与服务器的断开连接。 (3)服务器聊天室具有启动服务器,停止服务器,显示当前在线内 容 及 任 务 的用户功能。点击“启动”按钮实现与服务器的连接。点击“停止”按钮实现与服务器的断开连接。 (4)当服务器与客户机连接成功后。能够互相接受和发送消息。当多个客户机启动时,服务器会创建子线程处理对应线程的消息。 三、项目设计(研究)思路 (1)设计步骤:先画出聊天室的模型,布局。 (2)设计要点:设计主类与子类,分别实现不同的功能 (3)主要技术分析:需要掌握socket通信,swing和awt,io的简单应用. (4)解决思路:先按照草稿图设计出聊天室布局。再写各个类的功能。简单测试与修改代码。最后完善。 四、具体成果形式和要求 (见第三页) 进 度 起止日期 工作内容 2014.6.1-2014.6.2 绘出聊天室布局草稿图,查看资料 安 排 2014.6.3-2014.6.7 编写代码,初步实现各个类的功能,查看资料 2014.6.8-2014.6.16 查看资料,测试与完善各个功能。 主 要 参 考 资 料 1.Java2实用教程(第三版 ) 编著者 耿祥义 张跃平 清华大学出版社 2006 2.Java编程设计 编著者 刘海杰 中国铁道出版社 2006 3.Java网络编程精解 编著者 孙卫琴 电子工业出版社 指导教师 意见 系(教研(签字): 年 月 日 室)主任意(签字): 年 月 日 见

计算机网络课程设计说明书

学院名称: 计算机与信息工程学院 班级名称: 2012级物联网工程 学生姓名: 宋余保 学 号: 2012211466 题 目: 基于C/S的简单聊天室 指导教师姓名: 赵欢欢

起止日期: 2014.6.9-2014.6.15

一、 选题背景

使用Socket实现网上聊天功能。用户可以通过客户端连接到服务器端并进行网上聊天。聊天时可以启动多个客户端。

服务器端启动后,接收客户端发来的用户名和密码验证信息。验证通过则以当前的聊天客户列表信息进行响应;此后接收客户端发来的聊天信息,转发给客户端指定的聊天客户(即私聊)或所有其他客户端;在客户断开连接后公告其退出聊天系统的信息。

客户端启动后在GUI界面接收用户输入的服务器端信息、账号和密码等验证客户的身份。验证通过则显示当前系统在线客户列表。客户可以与指定对象进行私聊,也可以向系统中所有在线客户发送信息。

实现本程序需要了解网络基础知识,掌握C/S结构的工作特点,掌握数据结构、高级语言及网络编程知识,可以选择Visual C++、C或Java等语言实现。

二、方案设计

基于C/S的简单聊天室可以实现用户与服务器间,服务器与多个用户间的通信。

聊天室程序通常需要完成以下一些基本功能: (1)登录聊天室; (2)启动服务器; (3)关闭服务器; (4)用户之间的聊天; (5)退出聊天室。 本系统其体功能需求如下:

(1)聊天室管理员经登录界面登录到管理界而,即系统的服务器端。用户经

登录界而 都进入聊天大厅。

(2)不论是管理员还是用户都需一要在登录界面输入正确的用户名和密码后

才可以登录 到各自的界面中去。

(3)系统的两个主要界面都是为方便管理员和用户操作的。首先,管理员进

入到管理 界而后可以方便的启动/停止服务器,看到在线用户的信息和聊人信息、。用户进入到聊天 大厅中可以聊天,查看服务器状态。 (4) 一个用户退出聊天室对其他用户不能产生影响,而服务器断开与客户端

的连接则所有的用户都失去与服务器的连接。 (5)用户的聊天信息录入,重写,发送,接收方便,快捷。 (6)服务器状态,聊天信息和在线用户人数及时刷新。 (7)聊天室系统运行稳定、安全性高、

三、详细设计

服务器端

(1)首先实现的是服务器的GUI界面,如图3-1所示:

图3-1服务器GUI

代码如下:

// 构造放法

public Server() {

frame = new JFrame(\服务器\); contentArea = new JTextArea(); contentArea.setEditable(false);

contentArea.setForeground(Color.blue); txt_message = new JTextField(); txt_max = new JTextField(\); txt_port = new JTextField(\); btn_start = new JButton(\启动\); btn_stop = new JButton(\停止\); btn_send = new JButton(\发送\); btn_stop.setEnabled(false);

listModel = new DefaultListModel(); userList = new JList(listModel);

southPanel = new JPanel(new BorderLayout()); southPanel.setBorder(new TitledBorder(\写消息\)); southPanel.add(txt_message, \); southPanel.add(btn_send, \); leftPanel = new JScrollPane(userList);

leftPanel.setBorder(new TitledBorder(\在线用户\));

rightPanel = new JScrollPane(contentArea);

rightPanel.setBorder(new TitledBorder(\消息显示区\));

centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,

rightPanel);

centerSplit.setDividerLocation(100); northPanel = new JPanel();

northPanel.setLayout(new GridLayout(1, 6)); northPanel.add(new JLabel(\人数上限\)); northPanel.add(txt_max);

northPanel.add(new JLabel(\端口\)); northPanel.add(txt_port); northPanel.add(btn_start); northPanel.add(btn_stop);

northPanel.setBorder(new TitledBorder(\配置信息\));

frame.setLayout(new BorderLayout()); frame.add(northPanel, \);

frame.add(centerSplit, \); frame.add(southPanel, \); frame.setSize(600, 400);

//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏

int screen_width =

Toolkit.getDefaultToolkit().getScreenSize().width; int screen_height =

Toolkit.getDefaultToolkit().getScreenSize().height;

frame.setLocation((screen_width - frame.getWidth()) / 2, (screen_height - frame.getHeight()) / 2);

frame.setVisible(true); }

(2)其实实现服务器的启动代码如下

// 启动服务器

public void serverStart(int max, int port) throws java.net.BindException { try {

clients = new ArrayList(); serverSocket = new ServerSocket(port);

serverThread = new ServerThread(serverSocket, max); serverThread.start(); isStart = true;

} catch (BindException e) { isStart = false;

throw new BindException(\端口号已被占用,请换一个!\); } catch (Exception e1) { e1.printStackTrace(); isStart = false;

throw new BindException(\启动服务器异常!\);

}

(3)再次是实现服务器与客户机连接机制,如果有客户机申请连接,则为此客户机创建线程,代码如下:

// 服务器线程

class ServerThread extends Thread { private ServerSocket serverSocket; private int max;// 人数上限

// 服务器线程的构造方法

public ServerThread(ServerSocket serverSocket, int max) { this.serverSocket = serverSocket; this.max = max; }

public void run() {

while (true) {// 不停的等待客户端的链接 try {

Socket socket = serverSocket.accept(); if (clients.size() == max) {// 如果已达人数上限 BufferedReader r = new BufferedReader( new

InputStreamReader(socket.getInputStream()));

PrintWriter w = new PrintWriter(socket .getOutputStream()); // 接收客户端的基本用户信息 String inf = r.readLine();

StringTokenizer st = new StringTokenizer(inf, \); User user = new User(st.nextToken(), st.nextToken());

// 反馈连接成功信息

w.println(\服务器:对不起,\ + user.getName() + user.getIp() + \,服务器在线人数已达上限,请稍后尝试连接!\);

w.flush(); // 释放资源 r.close(); w.close(); socket.close(); continue; }

ClientThread client = new ClientThread(socket); client.start();// 开启对此客户端服务的线程 clients.add(client);

listModel.addElement(client.getUser().getName());// 更新在线列表

contentArea.append(client.getUser().getName() + client.getUser().getIp() + \上线!\\r\\n\); } catch (IOException e) { e.printStackTrace(); } } }

}

(4)再次是实现服务器的消息发送和接受的处理机制,代码如下:

public void run() {// 不断接收客户端的消息,进行处理。 String message = null; while (true) { try {

message = reader.readLine();// 接收客户端消息 if (message.equals(\))// 下线命令 {

+

}

线列表

ClientThread temp = temp.stop(); } } } dispatcherMessage(message); }

} e.printStackTrace(); } } }

contentArea.append(this.getUser().getName() this.getUser().getIp() + \下线!\\r\\n\); // 断开连接释放资源 reader.close(); writer.close(); socket.close(); // 向所有在线用户发送该用户的下线命令

for (int i = clients.size() - 1; i >= 0; i--) { clients.get(i).getWriter().println( \ + user.getName()); clients.get(i).getWriter().flush(); listModel.removeElement(user.getName());// 更新在// 删除此条客户端服务线程

for (int i = clients.size() - 1; i >= 0; i--) { if (clients.get(i).getUser() == user) { clients.get(i); clients.remove(i);// 删除此用户的服务线程 // 停止这条服务线程 return; else {

// 转发消息 catch (IOException e) { // 转发消息

public void dispatcherMessage(String message) {

StringTokenizer stringTokenizer = new StringTokenizer(message, \);

String source = stringTokenizer.nextToken(); String owner = stringTokenizer.nextToken(); String content = stringTokenizer.nextToken(); message = source + \说:\ + content; contentArea.append(message + \);

if (owner.equals(\)) {// 群发

for (int i = clients.size() - 1; i >= 0; i--) { clients.get(i).getWriter().println(message + \多人发送)\);

clients.get(i).getWriter().flush(); } } } }

}

客户端:

(1)首先是实现客户端的GUI 界面,如图3-2所示:

3-2 客户端GUI

代码如下:

public Client() {

textArea = new JTextArea(); textArea.setEditable(false);

textArea.setForeground(Color.blue); textField = new JTextField(); txt_port = new JTextField(\);

txt_hostIp = new JTextField(\); txt_name = new JTextField(\); btn_start = new JButton(\连接\); btn_stop = new JButton(\断开\); btn_send = new JButton(\发送\);

listModel = new DefaultListModel(); userList = new JList(listModel);

northPanel = new JPanel();

northPanel.setLayout(new GridLayout(1, 7)); northPanel.add(new JLabel(\端口\)); northPanel.add(txt_port);

northPanel.add(new JLabel(\服务器IP\)); northPanel.add(txt_hostIp);

northPanel.add(new JLabel(\姓名\)); northPanel.add(txt_name); northPanel.add(btn_start); northPanel.add(btn_stop);

northPanel.setBorder(new TitledBorder(\连接信息\));

rightScroll = new JScrollPane(textArea);

rightScroll.setBorder(new TitledBorder(\消息显示区\)); leftScroll = new JScrollPane(userList);

leftScroll.setBorder(new TitledBorder(\在线用户\)); southPanel = new JPanel(new BorderLayout()); southPanel.add(textField, \); southPanel.add(btn_send, \);

southPanel.setBorder(new TitledBorder(\写消息\));

centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll,

rightScroll);

centerSplit.setDividerLocation(100);

frame = new JFrame(\客户机\); // 更改JFrame的图标:

//

frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource(\

frame.setLayout(new BorderLayout()); frame.add(northPanel, \); frame.add(centerSplit, \); frame.add(southPanel, \); frame.setSize(600, 400); int screen_width =

Toolkit.getDefaultToolkit().getScreenSize().width; int screen_height =

Toolkit.getDefaultToolkit().getScreenSize().height;

frame.setLocation((screen_width - frame.getWidth()) / 2, (screen_height - frame.getHeight()) / 2); frame.setVisible(true); }

(2)其次是实现消息的接受和发送处理机制,代码如下: 不断接受服务器发来的消息以及处理消息的内容:

public void run() {

String message = \; while (true) { try {

message = reader.readLine();

StringTokenizer stringTokenizer = new StringTokenizer( message, \);

String command = stringTokenizer.nextToken();// 命令 if (command.equals(\))// 服务器已关闭命令 {

textArea.append(\服务器已关闭!\\r\\n\); closeCon();// 被动的关闭连接 return;// 结束线程

} else if (command.equals(\)) {// 有用户上线更新在线列表

String username = \; String userIp = \;

if ((username = stringTokenizer.nextToken()) != null && (userIp = stringTokenizer.nextToken()) != null) {

User user = new User(username, userIp); onLineUsers.put(username, user); listModel.addElement(username); }

} else if (command.equals(\)) {// 有用户下线更新在线列表

String username = stringTokenizer.nextToken(); User user = (User) onLineUsers.get(username); onLineUsers.remove(user);

listModel.removeElement(username);

} else if (command.equals(\)) {// 加载在线用户列表

int size = Integer

.parseInt(stringTokenizer.nextToken()); String username = null; String userIp = null;

for (int i = 0; i < size; i++) {

username = stringTokenizer.nextToken(); userIp = stringTokenizer.nextToken(); User user = new User(username, userIp); onLineUsers.put(username, user); listModel.addElement(username); }

} else if (command.equals(\)) {// 人数已达上限 textArea.append(stringTokenizer.nextToken() + stringTokenizer.nextToken() + \); closeCon();// 被动的关闭连接

JOptionPane.showMessageDialog(frame, \服务器缓冲区已满!\, \错误\,

JOptionPane.ERROR_MESSAGE); return;// 结束线程

} else {// 普通消息

textArea.append(message + \); }

} catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }

发送:btn_send.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { send(); } });

public void sendMessage(String message) {

writer.println(message); writer.flush(); }

(3)再次是实现客户端登陆界面的以及功能的实现,如图3-3所示:

3-3 登录界面

代码如下

public class LaunchClient extends JFrame implements ActionListener{ private static final String[] args = null;

String s1=\;//用户名 String s2=\;//密码 JPanel jp=new JPanel();

JTextField jtf=new JTextField();

JPasswordField jpf=new JPasswordField(\);

JLabel lab=new JLabel(\);//一个可以提示登陆成功或失败的标签lab JLabel lab1=new JLabel(\用户名\); JLabel lab2=new JLabel(\密 码\); JButton bt1=new JButton(\登录\); JButton bt2=new JButton(\重置\); public LaunchClient(){ super(\用户登录\); jp.setLayout(null);

/* jp.setBackground(Color.pink);*/

lab.setBounds(80,10,200,20);//设置x,y轴坐标,长度,宽度 lab1.setBounds(20,30,60,25); lab2.setBounds(20,70,60,25); jtf.setBounds(80,30,120,20); jpf.setBounds(80,70,120,20); bt1.setBounds(80, 100, 60,25); bt2.setBounds(141,100, 60,25); jp.add(lab1); jp.add(jtf); jp.add(lab2); jp.add(jpf); jp.add(bt1);

jp.add(bt2); jp.add(lab); add(jp);

lab1.setForeground(Color.blue); lab2.setForeground(Color.blue); bt1.setForeground(Color.blue); bt2.setForeground(Color.blue);

bt1.addActionListener(this);//注册监听器 bt2.addActionListener(this);

lab.setVisible(false);//验证之前 此标签lab暂时隐藏 jtf.setEditable(true );//文本框可以编辑 jpf.setEditable(true ); jp.setOpaque(false); this.setSize(240, 160); this.setVisible(true); setBack();//添加背景 }

@SuppressWarnings(\)

public void actionPerformed(ActionEvent e){

if(( jtf.getText().equals(s1))&&(jpf.getText().equals(s2))){//

如果输入的用户名和密码都正确 if(e.getSource()==bt1){

lab.setText(\正在登陆!\); //此时标签出现。。给予提示

lab.setVisible(true);//如果点击登陆

try { // 一段延时 Thread.sleep(1000);

} catch (InterruptedException e1) { }

// TODO 自动生成的 catch 块 e1.printStackTrace();

this.dispose(); //自动销毁当前窗口 new Client();

///new一个Client()对象,启动Client程序. } 空

else

if(e.getSource()==bt2){//如果点击重置按钮,将用户名和密码文本设为

jtf.setText(\); jpf.setText(\); }

}

else{

if(( !jtf.getText().equals(s1))&&(!jpf.getText().equals(s2))){//如

lab.setText(\用户名或密码错误!\);

果输入的文本不正确

}

lab.setForeground(Color.red);//此时标签出现。。给予提示

lab.setVisible(true); }

}

(4)最后是给客户端界面添加了一个背景图片

/**

public void setBack(){

ImageIcon iicon=new ImageIcon(\); JLabel lab_bg=new JLabel(iicon); add(lab_bg,-1);

lab_bg.setSize(240, 180); }

四、结果分析(或测试)

(1)首先启动服务器,如图4-1所示:

图4-1 服务器

(2)其次登陆客户端,如图4-2所示:

图 4-2 登陆界面

(3)验证通过之后会自动进入客户端聊天室,如图4-3所示:

图4-3 客户端界面

(4)下面是对话部分,如图4-4所示:

图4-4 聊天界面

五、结论(或总结)

两周的课程设计结束了,我的收获很大。通过课程设计的编程和对编程过程中遇到的问题的思考,有效的提高了我对数据结构的认识和理解,切实的提高了我的编程能力,补全了我的不足。通过这次课程设计,我巩固所了学过的知识,能用JAVA熟练地运用其中的一些,进一步掌握了各个指令的功能是转向。课程设计是对我们所学的这些东西一个综合的运用。在整个程序的编写中,调试占了很大部分的时间。要想写好程序,必须认真对待代码的每一个细节,还必须熟练

的掌握各种命令,这对程序的调试是非常重要的。通过这次实际动手能力的培养,我进一步熟悉了使用方法,基本达到了能独立阅读、编制和调试一定规模的水平。课程设计是对自己所学知识掌握程度最好的检验,特别是对于一些细节问题。考试还并不能完全的说明什么,因为考题都是一些单个的问题,大多只是知识的某一方面。而课程设计不同,我们要用到很多的单个知识点,把他们综合起来运用到自己的课题当中。学了一个学期的数据结构,现在终于迎来了课程设计,当然是一个很好的锻炼自己的机会。 在本次的课程设计也发现了自己很多的缺点不足之处,对于一些细节性的问题老犯错,特别是一个标点的错误,很急人。对于有些知识掌握的不行,有的是模模糊糊的不牢靠,虽然有的东西考试考过,但当它用到实际问题的时候,往往不知道用哪,放哪。实践出真知。课程设计是个实践,虽然实际不长,但给我们对知识的运用,利用都有了很好的发挥。人多力量大这句话是真理啊,不懂得地方问同学,不会的地方也问同学,自己努力的同时跟别人共同进步,这就是合作,学会合作是我们以后必备的重要的一项人际技能。一个程序的完成需要不断地修改才能够得到完善,人生正如那程序一样,只有不断地努力、奋斗、勇往直前,才能够完善自己,做最好的自己。 最后感谢同学的帮助,感谢老师的指导!

六、参考文献

1.Java2实用教程(第三版 ) 编著者 耿祥义 张跃平 清华大学出版社 2006 2.Java编程设计 编著者 刘海杰 中国铁道出版社 2006

3.Java网络编程精解 编著者 孙卫琴 电子工业出版社 :30-32.

学生签名: 填表日期: 年 月 日

本文来源:https://www.bwwdw.com/article/9wpf.html

Top