引言:这个程序是自从学习java以来写的第一个比较大的图形界面程序,花费了大约一周的时间,作为期末的课程设计,也算是基本上完成了任务,当然由于作者的编程能力有限,代码中难免存在BUG,不太简练,今天搬到博客上来,也算是对自己学习历程的一段记录吧,当然,如果我的这篇博客有幸被诸君看到,欢迎提出意见和建议,这篇博客仅仅作为我的一个记录吧,如果可能(估计也没时间了),将在后续版本中不断完善。所有源代码移步:http://download.csdn.net/detail/chengshijian2015/9724315

1设计要求
设计并实现一个基于TCP协议或者UDP协议的文字聊天软件,具体实现可以实现成类似于腾讯QQ式的,用户端通过登录服务器找到彼此,用户端通信时采用点对点,不用通过服务器转发,通信双方都可以主动发起连接或主动通信。
要求:
1、采用Windows应用程序风格,功能完整,显示直观,色彩协调,界面友好,操作简单。
2、设置在线用户列表,显示在线用户,并可以选择在线列表中的用户进行聊天。
3、用户端与服务器通信采用TCP协议;用户端与用户端通信采用UDP协议。
4、 一个用户端可以同时和多个其他用户端聊天。

2设计原理和技术
2.1 多线程
很多应用程序都存在对并发性的需求。例如,一个图形界面的应用程序希望在处理长时间任务的同时能快速响应用户的鼠标和键盘事件,一个在因特网上运行的服务程序希望能同时处理大量的客户请求。多线程(multithreading)为处理程序中的并发性提供了强有力的工具。
本程序主要通过两种方法创建线程:实现runnable接口,并重写里面的run()方法和直接继承Thread类,并重写里面的run(),实现多线程,其中实现Runnable接口时,亦主要是通过两种方法创建线程:直接创建类实现Runnable接口和直接在程序中创建一个继承式的匿名内部类,创建一个线程。
值得注意的是,在JVM环境中,用户程序以线程的形式来运行。当所有的非守护线程结束时,程序也就停止了。
2.2 图形用户界面
Java语言图形用户界面(Graphics User Interface,GUI)是实现用户与程序之间交互的一个控制面板,包含菜单、组件(或控件)。通过这种直观的图形界面接收用户的输入,显示程序运行结果。Java GUI从最初的抽象窗口工具包AWT(Abstract Window ToolKit),到后来的Swing组件,现在还有MyEclipse的SWT(Standard widget Toolkit)及构件基于SWT的JFace,满足不同时期、不同应用市场的需求。
2.3 网络编程
网络应用是Java语言取得成功的领域之一。Java提供了java.net包,其中包括一系列网络类,支持Java程序直接发送与接收TCP或UDP数据报。程序员使用这些类可轻松实现基于TCP和UDP的编程。
UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的特点,所以通常音频、视频和普通数据在传输中使用UDP较多,因为它们偶尔丢失一两个数据包,也不会对接收结果产生太大影响,所以本程序客户端与客户端的之间使用UDP传输。
TCP协议能为应用程序提供可靠的通信连接使一台计算机发出的字节流无差错的发送到其他电脑,对于可靠性要求高的数据通信往往使用TCP通信,所以本程序客户端与服务器端之间使用TCP传输。
3总体设计
本程序是一个模仿当前最流行的聊天软件QQ而设计的简单聊天软件。本程序采用面向对象程序分析设计方法,采用Java语言实现,设计了一个服务器端,和一个客户端,其中服务器与客户端之间采用TCP协议通信,客户端与客户端之间采用UDP协议通信,利用了Java的多线程技术编写而成。
程序主要采用14个Java类实现,共放在6个不同的包中。
程序中包和类的组织结构如图3-1所示:

图3-1 包和类的组织结构

————————————–所有的源代码————————————–
3详细设计及实现
3.1服务器端
3.1.1服务器主类ChatRoomServerMain

package server;public class ChatRoomServerMain
{/*** @author CSJ*/public static void main(String[] args){new ChatRoomServerFrame();}
}

3.1.2服务器框架类ChatRoomServerFrame

package server;import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import stream.ServerClientConnectionStream;
import user.UserInformation;public class ChatRoomServerFrame extends JFrame
{/*** @author CSJ*/private static final long serialVersionUID = 1L;private Map<String, ServerClientConnectionStream> userMap;private Set<UserInformation> userSet;private ServerSocket serverSocket;private JButton start;private JLabel welcome;private JTextArea hintInfo;private JTextArea onlineUserInfo;private JTextArea startInfoTextArea;public ChatRoomServerFrame(){super();userMap = new HashMap<String, ServerClientConnectionStream>();userSet = new HashSet<UserInformation>();welcome = new JLabel("服务器端");hintInfo = new JTextArea("当前状态:服务器未启动!\n");startInfoTextArea = new JTextArea();startInfoTextArea.setEditable(false);hintInfo.setEditable(false);onlineUserInfo = new JTextArea();onlineUserInfo.setEditable(false);createFrame();addEventHandler();}private void createFrame(){start = new JButton("启动服务器");JTabbedPane jTabbedPane = new JTabbedPane(JTabbedPane.TOP);JScrollPane hintPanel = new JScrollPane(hintInfo);JScrollPane onlineUserInfoPanel = new JScrollPane(onlineUserInfo);JScrollPane startInfoScrollPanel = new JScrollPane(startInfoTextArea);JPanel welcomePanel = new JPanel();welcomePanel.add(welcome);JPanel southPanel = new JPanel();southPanel.add(start);jTabbedPane.add("状态", hintPanel);jTabbedPane.add("运行详情", startInfoScrollPanel);jTabbedPane.add("在线用户详情", onlineUserInfoPanel);setSize(400, 600);setVisible(true);add(welcomePanel, BorderLayout.NORTH);add(jTabbedPane, BorderLayout.CENTER);add(southPanel, BorderLayout.SOUTH);Toolkit toolkit = Toolkit.getDefaultToolkit();Dimension screenSize = toolkit.getScreenSize();int height = getHeight();int width = getWidth();int screenWidth = screenSize.width / 2;int screenHeight = screenSize.height / 2;setLocation(screenWidth - width / 2, screenHeight - height / 2);}public void addEventHandler(){start.addActionListener(new ActionListener(){@Overridepublic void actionPerformed(ActionEvent arg0){try{serverSocket = new ServerSocket(9000);new Thread(new Runnable(){@Overridepublic void run(){startServer();}}).start();JOptionPane.showMessageDialog(null, "服务器已启动!");} catch (IOException e){JOptionPane.showMessageDialog(null, "服务器已启动!");e.printStackTrace();}}});addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e){int t = JOptionPane.showConfirmDialog(null, "确认要退出服务器吗?", "确认退出", JOptionPane.OK_CANCEL_OPTION);if (t == JOptionPane.OK_OPTION){System.exit(0);}}});}private void startServer(){while (true){try{System.out.println("开始监听客户端连接...");startInfoTextArea.append("开始监听客户端连接...\n");printServerInfo();Socket socket = serverSocket.accept();startInfoTextArea.append("已从客户端IP:" + socket.getInetAddress().getHostAddress() + ",端口号(TCP):"+ socket.getPort() + "接收到数据...\n");new Thread(new ChatRoomServerThread(new ServerClientConnectionStream(socket), userSet, userMap,hintInfo, startInfoTextArea, onlineUserInfo)).start();} catch (IOException e){e.printStackTrace();}} // while}private void printServerInfo(){hintInfo.setText("当前状态:开始监听客户端连接...");try{hintInfo.append("\n服务器名称:" + InetAddress.getLocalHost().getHostName());hintInfo.append("\n服务器IP地址:" + InetAddress.getLocalHost().getHostAddress());hintInfo.append("\n监听端口:9000");hintInfo.append("\n当前在线人数:" + userMap.size());} catch (UnknownHostException e){e.printStackTrace();}}
}

3.1.3服务器线程类ChatRoomServerThread

package server;import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
import javax.swing.JTextArea;
import stream.ServerClientConnectionStream;
import user.UserInformation;public class ChatRoomServerThread implements Runnable
{/*** @author CSJ*/private ServerClientConnectionStream userCS;private UserInformation userInfo;private Set<UserInformation> userSet;private Map<String, ServerClientConnectionStream> userMap;private StringBuffer userList;private JTextArea hintInfo;private JTextArea startInfoTextArea;private JTextArea onlineUserInfo;public ChatRoomServerThread(ServerClientConnectionStream userCS, Set<UserInformation> userSet,Map<String, ServerClientConnectionStream> userMap, JTextArea hintInfo, JTextArea startInfoTextArea,JTextArea onlineUserInfo){super();this.userCS = userCS;this.userSet = userSet;this.userMap = userMap;this.hintInfo = hintInfo;this.startInfoTextArea = startInfoTextArea;this.onlineUserInfo = onlineUserInfo;userList = new StringBuffer();userInfo = new UserInformation();}@Overridepublic void run(){while (true){String message = userCS.read();if (message.indexOf("%LOGIN%") == 0){userInfo.setInfo(message);// 标志 IP 端口号 姓名 账号 密码if (userMap.containsKey(userInfo.getAccount())){userCS.send("LOGIN_FIAL");} else if (userInfo.getName().equals("")){userCS.send("NAME_IS_NULL");} else{userMap.put(userInfo.getAccount(), userCS);userSet.add(userInfo);userCS.send("LOGIN_SUCESSFULLY");startInfoTextArea.append("客户端账号:" + userInfo.getAccount() + "登陆服务器登陆成功!\n");userList.append(userInfo.getAccount() + "&LOGIN:");sendCurrentUserList();}} else if (message.indexOf("%EXIT%") == 0){startInfoTextArea.append("服务器收到客户端账号:" + userInfo.getAccount() + "的退出请求...\n");userMap.remove(userInfo.getAccount());userSet.remove(userInfo);userList.append(userInfo.getAccount() + "&EXIT:");sendCurrentUserList();startInfoTextArea.append("已向客户端账号:" + userInfo.getAccount() + "发送了用户列表消息!\n");break;}}if (userCS != null){userCS.close();}}public void sendCurrentUserList(){System.out.println("正在向客户端发送用户列表消息...");onlineUserInfo.setText("");for (UserInformation userInfo : userSet){onlineUserInfo.append("账号:" + userInfo.getAccount() + ",密码:" + userInfo.getPassword() + ",昵称:"+ userInfo.getName() + ",IP地址:" + userInfo.getIP() + ",端口号(UDP):" + userInfo.getPort() + "\n");userList.append(userInfo.getIP() + "-" + userInfo.getPort() + "-" + userInfo.getAccount() + "-"+ userInfo.getName() + "-" + userInfo.getUserPortraitNum() + ",");}for (String string : userMap.keySet()){userMap.get(string).send("%USER_LIST%:" + userList);startInfoTextArea.append("服务器向" + string + "发送的用户列表为:%USER_LIST%:" + userList + "\n");}startInfoTextArea.append("已向客户端账号:" + userInfo.getAccount() + "发送了用户列表消息!\n");userList.delete(0, userList.length());printServerInfo();System.out.println("已更新了服务器状态信息!");startInfoTextArea.append("已更新了服务器状态信息!\n");}private void printServerInfo(){hintInfo.setText("当前状态:开始监听客户端连接...");try{hintInfo.append("\n服务器名称:" + InetAddress.getLocalHost().getHostName());hintInfo.append("\n服务器IP地址:" + InetAddress.getLocalHost().getHostAddress());hintInfo.append("\n监听端口:9000");hintInfo.append("\n当前在线人数:" + userMap.size());} catch (UnknownHostException e){e.printStackTrace();}}
}

3.1.4服务器到客户端连接流类ServerClientConnectionStream

package stream;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;public class ServerClientConnectionStream
{/*** @author CSJ*/private Socket socket;private BufferedReader reader;private PrintWriter writer;public ServerClientConnectionStream(Socket socket){super();this.socket = socket;getStream();}private void getStream(){try{reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));writer = new PrintWriter(socket.getOutputStream());} catch (IOException e){e.printStackTrace();}}public void close(){if (socket != null){try{socket.close();} catch (IOException e){e.printStackTrace();}}}public void send(String message){writer.println(message);writer.flush();}public String read(){try{return reader.readLine();} catch (IOException e){e.printStackTrace();}return null;}
}

3.2客户端
3.2.1客户端框架类ChatRoomClientFrame

package client;import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import readThread.ReadMessageFromClientThread;
import user.UserInformation;
import stream.ClientToClientConnectionStream;
import tools.MyMap;public class ChatRoomClientFrame extends JFrame implements ActionListener
{/*** @author CSJ*/private static final long serialVersionUID = 1L;private JTextArea chatTextArea;private JButton send;private JTextField inputField;private JLabel currentUserNameTitleLabel;private JTextArea userInfoListArea;private SimpleDateFormat simpleDateFormat;private UserInformation myUserInfo;private UserInformation toUserInfo;private JLabel userSignatureLable;private BufferedReader reader;private ClientToClientConnectionStream userDataCS;private ReadMessageFromClientThread readMessageFromClientThread;private Thread readMessageThread;private MyMap isOpenMap;private JPanel userInfoPanel;// 姓名 账户 IPpublic ChatRoomClientFrame(UserInformation toUserInfo, UserInformation myUserInfo, MyMap isOpenMap)throws HeadlessException{super("正在与" + toUserInfo.getName() + "(" + toUserInfo.getAccount() + ")" + "聊天中...");this.toUserInfo = toUserInfo;this.myUserInfo = myUserInfo;this.isOpenMap = isOpenMap;DatagramSocket dataSocket = null;try{dataSocket = new DatagramSocket();} catch (SocketException e){e.printStackTrace();}try{userDataCS = new ClientToClientConnectionStream(dataSocket, InetAddress.getByName(toUserInfo.getIP()),toUserInfo.getPort());} catch (UnknownHostException e){e.printStackTrace();}userDataCS.send("%TEST%");simpleDateFormat = (SimpleDateFormat) DateFormat.getInstance();simpleDateFormat.applyPattern("yyyy年MM月dd日HH时mm分ss秒");createFrame();addEventHandler();}private void createFrame(){chatTextArea = new JTextArea(25, 60);chatTextArea.setEditable(false);userInfoListArea = new JTextArea();userInfoListArea.setEditable(false);JScrollPane centerScrollPane = new JScrollPane(chatTextArea);send = new JButton("发送");inputField = new JTextField(35);currentUserNameTitleLabel = new JLabel(toUserInfo.getName() + "(" + toUserInfo.getAccount() + ")");currentUserNameTitleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));Random random = new Random();userInfoPanel = new JPanel(new GridLayout(2, 2, 5, 6));userInfoPanel.add(currentUserNameTitleLabel);try{reader = new BufferedReader(new FileReader(new File(new File("").getAbsolutePath() + File.separator + "res" + File.separator+ "signatures" + File.separator + "signature-" + (random.nextInt(8) + 1) + ".txt")));userSignatureLable = new JLabel(reader.readLine());userInfoPanel.add(userSignatureLable);} catch (FileNotFoundException e){e.printStackTrace();} catch (IOException e){e.printStackTrace();} finally{try{reader.close();} catch (IOException e){e.printStackTrace();}}userInfoListArea.setText("IP地址:" + toUserInfo.getIP() + "\n端口号(UDP):" + toUserInfo.getPort() + "\n昵称:"+ toUserInfo.getName() + "\n账户:" + toUserInfo.getAccount());ImageIcon portraItImage = new ImageIcon(getClass().getResource("\\pictures\\portrait-" + toUserInfo.getUserPortraitNum() + ".jpg"));portraItImage.setImage(portraItImage.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));JLabel portraItImageLable = new JLabel(portraItImage);JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));northPanel.add(portraItImageLable, BorderLayout.NORTH);JPanel southPanel = new JPanel();northPanel.add(userInfoPanel);southPanel.add(inputField);southPanel.add(send);JScrollPane listScrollPane = new JScrollPane(userInfoListArea);JPanel eastPanel = new JPanel(new BorderLayout());eastPanel.add(new JLabel("对方信息列表:"), BorderLayout.NORTH);eastPanel.add(listScrollPane, BorderLayout.CENTER);add(eastPanel, BorderLayout.EAST);add(northPanel, BorderLayout.NORTH);add(centerScrollPane, BorderLayout.CENTER);add(southPanel, BorderLayout.SOUTH);}@Overridepublic void actionPerformed(ActionEvent e){String message = inputField.getText();if (message == null || message.trim().equals("")){JOptionPane.showMessageDialog(this, "不能发送空消息!");} else{String time = simpleDateFormat.format(new Date());if (userDataCS != null){userDataCS.send(myUserInfo.getName() + "-" + myUserInfo.getAccount() + "-"+ myUserInfo.getUserPortraitNum() + "-" + myUserInfo.getRecenIP() + "-"+ myUserInfo.getRecentPort() + "-" + "(" + time + ")\n" + message);chatTextArea.append("我" + "(" + time + ")\n" + message + "\n");inputField.setText("");}}}private void addEventHandler(){inputField.addActionListener(this);send.addActionListener(this);addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e){int t = JOptionPane.showConfirmDialog(null, "确认要退出聊天室吗?", "确认退出", JOptionPane.OK_CANCEL_OPTION);if (t == JOptionPane.OK_OPTION){userDataCS.send("I_HAVE_EXIT_THE_WINDOW");try{Thread.sleep(100);} catch (InterruptedException e1){e1.printStackTrace();}readMessageThread.interrupt();readMessageFromClientThread.stopMe();isOpenMap.replace(toUserInfo.getAccount(), false);System.out.println("isOpenMap.replace(toUserInfo.getAccount()?" + toUserInfo.getAccount() + "--》"+ isOpenMap.getValue(toUserInfo.getAccount()));System.out.println("窗口已经关闭!");setDefaultCloseOperation(DISPOSE_ON_CLOSE);}}});}public ChatRoomClientFrame showMe(){pack();setVisible(true);setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);readMessageFromClientThread = new ReadMessageFromClientThread(userDataCS, chatTextArea, toUserInfo);readMessageThread = new Thread(readMessageFromClientThread);readMessageThread.start();return this;}public JTextArea getChatTextArea(){return chatTextArea;}public void setChatTextArea(JTextArea chatTextArea){this.chatTextArea = chatTextArea;}public ClientToClientConnectionStream getUserDataCS(){return userDataCS;}public void setUserDataCS(ClientToClientConnectionStream userDataCS){this.userDataCS = userDataCS;}
}

3.2.2客户端列表框架类ChatRoomUserListFrame

package client;import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import readThread.ReadMessageFromServerThread;
import stream.ClientToClientConnectionStream;
import stream.ServerClientConnectionStream;
import user.UserInformation;
import tools.MyMap;public class ChatRoomUserListFrame extends JFrame
{/*** @author CSJ*/private static final long serialVersionUID = 2L;private MyMap isOnlineMap;private MyMap isOpenMap;private ServerClientConnectionStream userCS;private JList<String> currentOnlineUserList;private Map<String, String> userInfoMap;private DatagramSocket dataSocket;private UserInformation userInfo;private ReadMessageFromServerThread readMessageFromServerThread;private Thread readMessagehread;private ChatRoomClientFrame chatRoomClientFrame;private Map<String, ChatRoomClientFrame> chatRoomMap = new HashMap<String, ChatRoomClientFrame>();public ChatRoomUserListFrame(ServerClientConnectionStream userCS, UserInformation userInfo) throws HeadlessException{super("MYQQ精简版V1.0");this.userCS = userCS;this.userInfo = userInfo;initData();createFrame();addEventHandler();autoListening();}private void initData(){isOnlineMap = new MyMap();isOpenMap = new MyMap();userInfoMap=new HashMap<String, String>();try{dataSocket = new DatagramSocket(userInfo.getPort());} catch (SocketException e){e.printStackTrace();}}private void createFrame(){currentOnlineUserList = new JList<String>();currentOnlineUserList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);ImageIcon portraItImage = new ImageIcon(getClass().getResource("\\pictures\\portrait-" + userInfo.getUserPortraitNum() + ".jpg"));portraItImage.setImage(portraItImage.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));JLabel portraItImageLable = new JLabel(portraItImage);JScrollPane listScrollPane = new JScrollPane(currentOnlineUserList);JPanel centerPanel = new JPanel(new BorderLayout());JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));northPanel.add(portraItImageLable, BorderLayout.NORTH);JPanel userInfoPanel = new JPanel(new GridLayout(2, 2, 5, 10));Calendar calendar = Calendar.getInstance();int hour = calendar.get(Calendar.HOUR_OF_DAY);JLabel userInfoLable = new JLabel(hour < 6 ? "凌晨好," + userInfo.getName(): (hour < 12 ? "上午好," : (hour < 18 ? "下午好," : "晚上好,")) + userInfo.getName());userInfoPanel.add(userInfoLable);SimpleDateFormat simpleDateFormat = (SimpleDateFormat) DateFormat.getInstance();simpleDateFormat.applyPattern("yyyy年MM月dd日    E");JLabel userTimeLable = new JLabel(simpleDateFormat.format(new Date()));userInfoPanel.add(userTimeLable);northPanel.add(userInfoPanel);centerPanel.add(new JLabel("在线用户列表:"), BorderLayout.CENTER);centerPanel.add(listScrollPane, BorderLayout.CENTER);add(northPanel, BorderLayout.NORTH);add(centerPanel, BorderLayout.CENTER);Toolkit toolkit = Toolkit.getDefaultToolkit();Dimension screenSize = toolkit.getScreenSize();int width = getWidth();int screenWidth = screenSize.width / 2;setLocation(screenWidth - width / 2, 0);setResizable(false);}public void autoListening(){final ClientToClientConnectionStream userDataSoketCS = new ClientToClientConnectionStream(dataSocket);new Thread(new Runnable(){@Overridepublic void run(){while (true){String string = userDataSoketCS.read();System.out.println("自动监听读取到:" + string + "端口号:" + userDataSoketCS.getUserReceivePacket().getPort());if (!"%TEST%".equals(string) && !"I_HAVE_EXIT_THE_WINDOW".equals(string)){String tString[] = string.split("-");if (isOpenMap.getValue(tString[1]) == true){chatRoomMap.get(tString[1]).getUserDataCS().setHostAddress(userDataSoketCS.getUserReceivePacket().getAddress());chatRoomMap.get(tString[1]).getUserDataCS().setPort(userDataSoketCS.getUserReceivePacket().getPort());chatRoomMap.get(tString[1]).getUserDataCS().send("%TEST%");chatRoomMap.get(tString[1]).getChatTextArea().append(string + "\n");} else{int t = JOptionPane.showConfirmDialog(null, tString[0] + "给您发来一条消息,是否查收?", "确认",JOptionPane.YES_NO_OPTION);if (t == JOptionPane.YES_OPTION){UserInformation toUserInfo = new UserInformation(tString[0], tString[1],userDataSoketCS.getUserReceivePacket().getAddress().getHostAddress(),userDataSoketCS.getUserReceivePacket().getPort(), Integer.parseInt(tString[2]),tString[3], Integer.parseInt(tString[4]));chatRoomClientFrame = new ChatRoomClientFrame(toUserInfo, userInfo, isOpenMap).showMe();StringBuffer tMessage = new StringBuffer();tMessage.append(tString[0]);tMessage.append(tString[5]);chatRoomClientFrame.getChatTextArea().append(tMessage + "\n");isOpenMap.replace(tString[1], true);chatRoomMap.put(tString[1], chatRoomClientFrame);}}}}}}).start();}private void addEventHandler(){currentOnlineUserList.addListSelectionListener(new ListSelectionListener(){@Overridepublic void valueChanged(ListSelectionEvent e){if (!e.getValueIsAdjusting()){String tString = (String) currentOnlineUserList.getSelectedValue();if (tString != null){String t[] = tString.split("(");String[] string = t[1].split(")");// 姓名-账号-IP-端口if (string[0].equals(userInfo.getAccount())){JOptionPane.showMessageDialog(null, "不能选择自己!");} else{String tempUserInfo[]= userInfoMap.get(string[0]).split("-");UserInformation toUserInfo = new UserInformation(tempUserInfo[3], tempUserInfo[2], tempUserInfo[0],Integer.parseInt(tempUserInfo[1]), Integer.parseInt(tempUserInfo[4]), tempUserInfo[0],Integer.parseInt(tempUserInfo[1]));chatRoomClientFrame = new ChatRoomClientFrame(toUserInfo, userInfo, isOpenMap);chatRoomClientFrame.showMe();chatRoomMap.put(tempUserInfo[1], chatRoomClientFrame);isOpenMap.replace(tempUserInfo[1], true);}}}}});addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e){int t = JOptionPane.showConfirmDialog(null, "确认要退出客户端吗?\n温馨提示:退出会同时关闭所有聊天窗口", "确认退出",JOptionPane.OK_CANCEL_OPTION);if (t == JOptionPane.OK_OPTION){readMessagehread.interrupt();readMessageFromServerThread.stopMe();userCS.send("%EXIT%:" + userInfo.getAccount());try{Thread.sleep(100);} catch (InterruptedException e1){e1.printStackTrace();}userCS.send("%EXIT%:" + userInfo.getAccount());try{Thread.sleep(100);} catch (InterruptedException e1){e1.printStackTrace();}System.exit(0);}}});}public void showMe(){setSize(340, 700);setVisible(true);setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);readMessageFromServerThread = new ReadMessageFromServerThread(userCS,  userInfoMap, currentOnlineUserList,isOnlineMap, isOpenMap);readMessagehread = new Thread(readMessageFromServerThread);readMessagehread.start();}
}

3.2.3客户端登陆界面类LoginFrame

package client;import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import stream.ServerClientConnectionStream;
import user.UserInformation;public class LoginFrame extends JFrame
{/*** @author CSJ*/private static final long serialVersionUID = 1L;private final int SERVER_PORT = 9000;private ServerClientConnectionStream userCS;private String userName;private int userPort;private JLabel register;private JLabel findPassword;private JCheckBox remPassword;private JCheckBox autoLogin;private String message;private JTextField accountField;private JPasswordField passwordField;private JPanel jPanel_1;private JPanel jPanel_2;private JPanel jPanel_3;private JButton login;private Socket socket;private InetAddress SERVER_INETADRESS;private InetAddress LOCAL_INETADRESS;private UserInformation userInfo;public LoginFrame() throws HeadlessException{initData();createFrame();addHandlerEvent();}@SuppressWarnings("resource")private void initData(){userInfo = new UserInformation();try{DatagramSocket d = new DatagramSocket();userPort = d.getLocalPort();d.close();SERVER_INETADRESS = InetAddress.getLocalHost();LOCAL_INETADRESS = InetAddress.getLocalHost();socket = new Socket(SERVER_INETADRESS, SERVER_PORT, LOCAL_INETADRESS, new DatagramSocket().getLocalPort());userCS = new ServerClientConnectionStream(socket);} catch (UnknownHostException e){System.out.println("找不到 host 的任何 IP 地址!");e.printStackTrace();} catch (IOException e){System.out.println("创建套接字时发生 I/O 错误!");e.printStackTrace();System.exit(1);}}private void createFrame(){setTitle("登陆");Random random = new Random();ImageIcon image1 = new ImageIcon(getClass().getResource("\\pictures\\qq.png"));JLabel imageLable = new JLabel(image1);int num = (random.nextInt(38) + 1);userInfo.setUserPortraitNum(num);ImageIcon portraItImage = new ImageIcon(getClass().getResource("\\pictures\\portrait-" + num + ".jpg"));portraItImage.setImage(portraItImage.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));JLabel portraItImageLable = new JLabel(portraItImage);JPanel mainLayout = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));accountField = new JTextField(15);login = new JButton("安全登录");login.setBackground(new Color(30, 144, 255));login.setForeground(Color.white);login.setPreferredSize(new Dimension(170, 30));passwordField = new JPasswordField(15);JPanel jPanel_0 = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));JPanel accRes = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));JPanel passRes = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));JPanel accPassHintPanel = new JPanel(new GridLayout(3, 15, 0, 0));register = new JLabel("注册账号");register.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));register.setForeground(Color.BLUE);findPassword = new JLabel("找回密码");findPassword.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));findPassword.setForeground(Color.BLUE);remPassword = new JCheckBox("记住密码");autoLogin = new JCheckBox("自动登录");accRes.add(accountField);accRes.add(register);passRes.add(passwordField);passRes.add(findPassword);accPassHintPanel.add(accRes);accPassHintPanel.add(passRes);jPanel_1 = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 10));jPanel_2 = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 1));jPanel_3 = new JPanel();jPanel_0.add(imageLable);jPanel_3.add(login);jPanel_2.add(remPassword);jPanel_2.add(autoLogin);accPassHintPanel.add(jPanel_2);mainLayout.add(jPanel_0);jPanel_1.add(portraItImageLable);jPanel_1.add(accPassHintPanel);mainLayout.add(jPanel_1);mainLayout.add(jPanel_3);add(mainLayout);setVisible(true);setSize(445, 350);setDefaultCloseOperation(DISPOSE_ON_CLOSE);Toolkit toolkit = Toolkit.getDefaultToolkit();Dimension screenSize = toolkit.getScreenSize();int height = getHeight();int width = getWidth();int screenWidth = screenSize.width / 2;int screenHeight = screenSize.height / 2;setLocation(screenWidth - width / 2, screenHeight - height / 2);setDefaultCloseOperation(DISPOSE_ON_CLOSE);}private void addHandlerEvent(){login.addActionListener(new ActionListener(){// 标志 IP 端口号 姓名 账号 密码@Overridepublic void actionPerformed(ActionEvent arg0){System.out.println("已开始向服务器发送登录数据...");try{userCS.send("%LOGIN%:" + InetAddress.getLocalHost().getHostAddress() + ":" + userPort + ":" + ""+ ":" + accountField.getText() + ":" + String.valueOf(passwordField.getPassword()).trim()+ ":" + userInfo.getUserPortraitNum());} catch (UnknownHostException e){e.printStackTrace();}System.out.println("等待服务器返回登录结果...");new Thread(new Runnable(){@Overridepublic void run(){while (true){message = userCS.read();if ("LOGIN_FIAL".equals(message)){JOptionPane.showMessageDialog(null, "已有相同的账号,请重新输入");accountField.setText("");passwordField.setText("");} else if ("NAME_IS_NULL".equals(message)){// setVisible(false);dispose();userName = JOptionPane.showInputDialog(null, "来给自己起个名字吧");try{// 标志 IP 端口号 姓名 账号 密码userCS.send("%LOGIN%:" + InetAddress.getLocalHost().getHostAddress() + ":"+ userPort + ":" + userName + ":" + accountField.getText() + ":"+ String.valueOf(passwordField.getPassword()).trim() + ":"+ userInfo.getUserPortraitNum());userInfo.setIP(InetAddress.getLocalHost().getHostAddress());userInfo.setRecenIP(InetAddress.getLocalHost().getHostAddress());userInfo.setRecentPort(userPort);System.out.println("已向服务器重新发送了信息...");} catch (UnknownHostException e){e.printStackTrace();}} else if ("LOGIN_SUCESSFULLY".equals(message)){setDefaultCloseOperation(DISPOSE_ON_CLOSE);userInfo.setAccount(accountField.getText());userInfo.setName(userName);userInfo.setPort(userPort);LoginProcess loginProcess = new LoginProcess(userInfo.getUserPortraitNum());try{Thread.sleep(2000);} catch (InterruptedException e){e.printStackTrace();}loginProcess.dispose();new ChatRoomUserListFrame(userCS, userInfo).showMe();JOptionPane.showMessageDialog(null, "登录成功!");}}}}).start();}});register.addMouseListener(new MouseListener(){@Overridepublic void mouseClicked(MouseEvent e){JOptionPane.showMessageDialog(null, "本功能暂未开放!");}@Overridepublic void mouseEntered(MouseEvent e){}@Overridepublic void mouseExited(MouseEvent e){}@Overridepublic void mousePressed(MouseEvent e){}@Overridepublic void mouseReleased(MouseEvent e){}});findPassword.addMouseListener(new MouseListener(){@Overridepublic void mouseReleased(MouseEvent e){}@Overridepublic void mousePressed(MouseEvent e){}@Overridepublic void mouseExited(MouseEvent e){}@Overridepublic void mouseEntered(MouseEvent e){}@Overridepublic void mouseClicked(MouseEvent e){JOptionPane.showMessageDialog(null, "本功能暂未开放!");}});remPassword.addActionListener(new ActionListener(){@Overridepublic void actionPerformed(ActionEvent e){JOptionPane.showMessageDialog(null, "本功能暂未开放!");}});autoLogin.addActionListener(new ActionListener(){@Overridepublic void actionPerformed(ActionEvent e){JOptionPane.showMessageDialog(null, "本功能暂未开放!");}});addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e){System.exit(0);}});}
}

3.2.4客户端登陆主类LoginMain

package client;public class LoginMain
{/*** @author CSJ*/public static void main(String[] args){new LoginFrame();}
}

3.2.5客户端登陆过程类LoginProcess

package client;import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;public class LoginProcess extends JFrame
{/*** @author CSJ*/private static final long serialVersionUID = 1L;public LoginProcess(int number){super();setTitle("登陆");ImageIcon image1 = new ImageIcon(getClass().getResource("\\pictures\\qq.png"));JLabel imageLable = new JLabel(image1);ImageIcon portraItImage = new ImageIcon(getClass().getResource("\\pictures\\portrait-" + number + ".jpg"));portraItImage.setImage(portraItImage.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));JLabel portraItImageLable = new JLabel(portraItImage);JPanel mainLayout = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));JPanel jPanel_0 = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));JPanel jPanel_1 = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 10));JPanel jPanel_2 = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));JButton login = new JButton("正在登录...");login.setPreferredSize(new Dimension(170, 30));login.setForeground(Color.white);login.setBackground(new Color(30, 144, 255));jPanel_2.add(login);jPanel_0.add(imageLable);mainLayout.add(jPanel_0);jPanel_1.add(portraItImageLable);JPanel jPanel_3 = new JPanel(new GridLayout(2, 1, 5, 5));jPanel_3.add(jPanel_1);jPanel_3.add(jPanel_2);mainLayout.add(jPanel_3);add(mainLayout);setSize(445, 350);setDefaultCloseOperation(DISPOSE_ON_CLOSE);Toolkit toolkit = Toolkit.getDefaultToolkit();Dimension screenSize = toolkit.getScreenSize();int height = getHeight();int width = getWidth();int screenWidth = screenSize.width / 2;int screenHeight = screenSize.height / 2;setLocation(screenWidth - width / 2, screenHeight - height / 2);setVisible(true);}
}

3.2.6客户端读取客户端消息线程类ReadMessageFromClientThread

package readThread;import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.swing.JTextArea;
import stream.ClientToClientConnectionStream;
import user.UserInformation;public class ReadMessageFromClientThread implements Runnable
{/*** @author CSJ*/private ClientToClientConnectionStream userDataCS;private JTextArea chatTextArea;private UserInformation toUserInfo;private volatile boolean stop = false;public ReadMessageFromClientThread(ClientToClientConnectionStream userDataCS, JTextArea chatTextArea,UserInformation toUserInfo){super();this.userDataCS = userDataCS;this.chatTextArea = chatTextArea;this.toUserInfo = toUserInfo;}@Overridepublic void run(){while (!stop){synchronized (this){System.out.println("客户端--客户端读取消息线程已启动!");if (userDataCS != null){String message = userDataCS.read();System.out.println(message);if ("%TEST%".equals(message)){System.out.println("客户端中原IP:" + userDataCS.getHostAddress() + "原端口:" + userDataCS.getPort());userDataCS.setHostAddress(userDataCS.getUserReceivePacket().getAddress());userDataCS.setPort(userDataCS.getUserReceivePacket().getPort());System.out.println("客户端中现IP:" + userDataCS.getHostAddress() + "现在端口:" + userDataCS.getPort());} else if ("I_HAVE_EXIT_THE_WINDOW".equals(message)){try{userDataCS.setHostAddress(InetAddress.getByName(toUserInfo.getRecenIP()));userDataCS.setPort(toUserInfo.getRecentPort());} catch (UnknownHostException e){e.printStackTrace();}} else{String tString[] = message.split("-");System.out.println("客户端--客户端(IP:" + userDataCS.getHostAddress() + "端口(UDP):"+ userDataCS.getPort() + ")读取到消息:" + message);StringBuffer tMessage = new StringBuffer();tMessage.append(tString[0]);tMessage.append(tString[5]);chatTextArea.append(tMessage + "\n");}}}}}public void stopMe(){stop = true;}
}

3.2.7客户端读取服务器消息线程类ReadMessageFromServerThread

package readThread;import java.util.Map;import javax.swing.JList;
import javax.swing.JOptionPane;import stream.ServerClientConnectionStream;
import tools.MyMap;public class ReadMessageFromServerThread implements Runnable {/*** @author CSJ*/private ServerClientConnectionStream userCS;private String onlineUserList[];private MyMap isOnlineMap;private JList<String> currentOnlineUserList;private volatile boolean stop = false;private MyMap isOpenMap;private Map<String, String> userInfoMap;private String loginName;public ReadMessageFromServerThread(ServerClientConnectionStream userCS,Map<String, String> userInfoMap, JList<String> currentOnlineUserList,MyMap isOnlineMap, MyMap isOpenMap) {super();this.userCS = userCS;this.userInfoMap=userInfoMap;this.isOnlineMap = isOnlineMap;this.isOpenMap = isOpenMap;this.currentOnlineUserList = currentOnlineUserList;}public void refreshGUIUserList() {StringBuffer t = new StringBuffer();System.out.println("在服务器--客户端线程中刷新用户界面!");for (String string : onlineUserList){// 姓名 账号 IP-端口 头像序号--String per[] = string.split("-");if (!per[2].equals(loginName)){System.out.println(per[2]);isOnlineMap.put(per[2], false);isOpenMap.put(per[2], false);}t.append(per[3] + "(" + per[2]+ ")"+":");userInfoMap.put(per[2], string);}String tt[] = t.toString().split(":");currentOnlineUserList.setListData(tt);}@Overridepublic void run(){while (!stop){System.out.println("服务器--客户端读取消息线程已启动!");String message = userCS.read();if (message != null){System.out.println("服务器--客户端读取消息线程已启动!" + message);String perMessage[] = message.split(":");loginName = perMessage[1];if ("%USER_LIST%".equals(perMessage[0])){onlineUserList = perMessage[2].split(",");if ("LOGIN".equals(perMessage[1].split("&")[1])){isOnlineMap.put(perMessage[1].split("&")[0], true);isOpenMap.put(perMessage[1].split("&")[0], false);} else if ("EXIT".equals(perMessage[1].split("&")[1])){if (isOpenMap.getValue(perMessage[1].split("&")[0]) == true){JOptionPane.showMessageDialog(null, "对方已离线!");}isOnlineMap.replace(perMessage[1].split("&")[0], false);isOpenMap.replace(perMessage[1].split("&")[0], false);}refreshGUIUserList();}}}}public void stopMe() {stop = true;}
}

3.2.8客户端到客户端连接流类ClientToClientConnectionStream

package stream;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
import java.io.UnsupportedEncodingException;public class ClientToClientConnectionStream
{/*** @author CSJ*/private DatagramPacket userReceivePacket;private DatagramSocket userDataSocket;private byte buffer[];private InetAddress hostAddress;private int port;public ClientToClientConnectionStream(DatagramSocket userDataSocket){super();this.userDataSocket = userDataSocket;buffer = new byte[1024];userReceivePacket = new DatagramPacket(buffer, buffer.length);}public ClientToClientConnectionStream(DatagramSocket userDataSocket, InetAddress hostAddress, int port){super();this.hostAddress = hostAddress;this.port = port;this.userDataSocket = userDataSocket;buffer = new byte[1024];userReceivePacket = new DatagramPacket(buffer, buffer.length);}public void send(String message){try{userDataSocket.send(new DatagramPacket(message.getBytes(), message.getBytes().length, hostAddress, port));} catch (IOException e){System.out.println("UDP端口被占用!");e.printStackTrace();}}public String read(){try{if (!userDataSocket.isClosed()){userDataSocket.receive(userReceivePacket);System.out.print("liu现在端口号:" + userReceivePacket.getPort());String string = new String(userReceivePacket.getData(), 0, userReceivePacket.getLength(), "GBK");return string;}} catch (UnsupportedEncodingException e){System.out.println("不支持的编码类型!");e.printStackTrace();} catch (IOException e){System.out.println(userDataSocket == null);e.printStackTrace();}return null;}public void close(){if (userDataSocket != null){userDataSocket.close();}}public void setPort(int port){this.port = port;}public String getHostAddress(){return hostAddress.getHostAddress();}public void setHostAddress(InetAddress hostAddress){this.hostAddress = hostAddress;}public int getPort(){return port;}public DatagramPacket getUserReceivePacket(){return userReceivePacket;}public InetAddress getInetAddress(){return userReceivePacket.getAddress();}public DatagramSocket getDatagramSocket(){return userDataSocket;}}

3.2.9客户端自定义的工具类MyMap

package tools;import java.util.HashMap;
import java.util.Map;
import java.util.Observable;public class MyMap extends Observable
{/*** @author CSJ*/private Map<String, Boolean> myMap;public MyMap(){super();myMap = new HashMap<String, Boolean>();}public MyMap(String key, boolean value){super();myMap = new HashMap<String, Boolean>();myMap.put(key, value);  }public void put(String key, boolean value){myMap.put(key, value);setChanged();notifyObservers();}public void replace(String key, boolean value){myMap.remove(key);myMap.put(key, value);setChanged();notifyObservers();}public Map<String, Boolean> getIsOnlineMap(){return myMap;}public void setIsOnlineMap(Map<String, Boolean> isOnlineMap){this.myMap = isOnlineMap;}public boolean getValue(String key){return myMap.get(key);}public void remove(String key){myMap.remove(key);}public boolean containsValue(String key){return myMap.containsValue(key);}
}

3.2.10客户端用户信息类UserInformation

package user;public class UserInformation
{/*** @author CSJ*/private String name;private String account;private String password;private String IP;private int port;private int recentPort;private String recenIP;private int userPortraitNum;public UserInformation(){super();}public UserInformation(String name, String account, String password, String IP, int port, int userPortraitNum){super();this.name = name;this.account = account;this.password = password;this.IP = IP;this.port = port;this.userPortraitNum = userPortraitNum;}public UserInformation(String name, String account, String IP, int port, int userPortraitNum, String recentIP,int recentPort){super();this.name = name;this.account = account;this.IP = IP;this.port = port;this.recenIP = recentIP;this.recentPort = recentPort;this.userPortraitNum = userPortraitNum;}public int getRecentPort(){return recentPort;}public void setRecentPort(int recentPort){this.recentPort = recentPort;}public String getRecenIP(){return recenIP;}public void setRecenIP(String recenIP){this.recenIP = recenIP;}public UserInformation(String name, int port){super();this.name = name;this.port = port;}public String getName(){return name;}public void setName(String name){this.name = name;}public String getAccount(){return account;}public void setAccount(String acocount){this.account = acocount;}public String getPassword(){return password;}public void setPassword(String password){this.password = password;}public String getIP(){return IP;}public void setIP(String iP){IP = iP;}public int getPort(){return port;}public void setPort(int port){this.port = port;}public int getUserPortraitNum(){return userPortraitNum;}public void setUserPortraitNum(int userPortraitNum){this.userPortraitNum = userPortraitNum;}public UserInformation setInfo(String message){// 标志 IP 端口号 姓名 账号 密码this.IP = message.split(":")[1];this.port = Integer.parseInt(message.split(":")[2]);this.name = message.split(":")[3];this.account = message.split(":")[4];this.password = message.split(":")[5];this.userPortraitNum = Integer.parseInt(message.split(":")[6]);return this;}
}

5测试

图5-1 服务器界面

图5-2服务器启动界面

图5-3用户登录界面(用户:巴黎夜雨)

图5-4 创建昵称界面(用户:巴黎夜雨)

图5-5 登录过程界面(用户:巴黎夜雨)

图5-6 登录成功界面(用户:巴黎夜雨)

图5-7用户登录界面(用户:甜心百分百)

图5-8 创建昵称界面(用户:甜心百分百)

图5-9 登录过程界面(用户:甜心百分百)

图5-10 登录成功界面(用户:甜心百分百)

图5-11 用户登录界面(用户:执手不忆殇)

图5-12 创建昵称界面(用户:执手不忆殇)

图5-13 登录过程界面(用户:执手不忆殇)

图5-14 登录成功界面(用户:执手不忆殇)

图5-15当前的三个用户

图5-16 执手不忆殇找巴黎夜雨聊天

图5-17 巴黎夜雨接弹出消息提示

图5-18 巴黎夜雨选择是,弹出聊天窗口

图5-19 聊天截图

图5-20 执手不忆殇关闭了与巴黎夜雨的聊天窗口,巴黎夜雨弹出提示消息

图5-21巴黎夜雨关闭了聊天窗口,又选择和甜心百分百聊天

图5-22 甜心百分百弹出消息提示后,选择是,两人开始聊天

图5-23 聊天截图

图5-24三人下线后,服务器的运行情况


图5-25 服务器运行详情截图

6结束语
本课程设计采用Java编程语言实现,在Eclipse Java Neon上编译通过。通过本次课程设计,我对Java语言有了更深入的理解,对后续课程的学习及实际工作中一定会带来很大的帮助。同时,本程序还存在一定的不足之处,如果可能,将在后续版本中不断完善。

参考文献
 赵新慧 等. Java程序设计教程,清华大学出版社,2014
 网络编程相关资料
电子文档:
第11章 网络编程.ppt
JDK_API_1_6_zh_CN.CHM

初学java之模拟QQ聊天软件(简单实现)相关推荐

  1. python软件代码示例-用Python写一个模拟qq聊天小程序的代码实例

    Python 超简单的聊天程序 客户端: import socket, sys host = '10.248.27.23' # host = raw_input("Plz imput des ...

  2. 仿QQ聊天软件(登录界面、好友界面、聊天界面)-Java(Swing、Socket)

    文章目录 一.项目结构 二.项目功能 三.制作界面 (一).登录界面的制作 (二).好友列表界面 (三).聊天界面 四.制作服务器 五.设计通信协议 六.项目缺点 学习了socket通信后,就想来制作 ...

  3. webSocket整理(二)--webSocket的模拟qq聊天案例

    一 前言 前面一篇大致讲解了webSocket的定义以及配置,那么这一篇通过简单案例对webSocket更好的理解与使用.使用的是spring-servlet-webSocket的整合形式.因为这里主 ...

  4. 转载:仿QQ聊天软件2.0版

    仿QQ聊天软件2.0版 这是大神的地址:牟尼的专栏 http://blog.csdn.net/u012027907 详细的过程本人没看,但是看见他的实现效果,相当诱人!     上次课设做了Java版 ...

  5. 模拟QQ聊天小项目收尾---界面展示服务端与客户端进行信息交互(用到的知识:io,线程,Swing界面,面向对象思想...... )

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文学到有用的干货知识,那么请您尽量点赞,关注,评论,收藏 这两天我一直在设计这 ...

  6. 用python做毕业设计小程序_用Python写一个模拟qq聊天小程序的代码实例

    Python 超简单的聊天程序 客户端: import socket, sys host = '10.248.27.23' # host = raw_input("Plz imput des ...

  7. webqq2协议分析和qq聊天机器人简单实现(转)

    webqq2协议分析和qq聊天机器人简单实现 转之http://hfutxf.javaeye.com/blog/800866 通过webqq接口,可以实现发送qq消息接收qq消息等,这样,想实现一个q ...

  8. 如何利用python实现qq聊天_用Python写一个模拟qq聊天小程序的代码实例

    Python 超简单的聊天程序 客户端: import socket, sys host = '10.248.27.23' # host = raw_input("Plz imput des ...

  9. Java程序模拟QQ空间登录 - 并模拟刷说说的赞(图文) 注意:腾讯修改了加密算法,已失效(2015-01-31)

    Java程序模拟QQ空间登录 - 并模拟刷说说的赞 背景:在2013-10-25的一天,有个friend在QQ问我:"post登陆QQ空间抓取不到post的数据".于是故事就开始了 ...

最新文章

  1. 科大讯飞和百度语音平台语音识别Java调用记录
  2. python的起源和发展_Python入门第一课——Python的起源、发展与前景!
  3. php对象存储hadoop存储,三个理由告诉你对象存储替换HDFS还不错
  4. seaborn常用速查手册
  5. APACHE服务器出现No input file specified.解决方案
  6. 用FTP命令实现自动下载和上载文件
  7. goback history 传递参数_vue-router go(-1)后退时怎么带参数?
  8. java发送邮件带附件
  9. 计算机怎么清理CAD,注册表cad,如何清理cad软件在注册表残留
  10. 分解质因数_java
  11. 组合排列中重复数问题
  12. css3 呼吸的莲花_心肾呼吸法—莲花能量冥想*
  13. 30岁学前端晚不晚?别被年龄定义你的人生!
  14. trackerslist GitHub12月无重复更新版
  15. Python搭建SVM
  16. 桌面应用程序脚本录制
  17. JDG人脸识别课堂管理系统全栈开发流程报告-软件工程实践报告
  18. 【Java】【系列篇】【Spring源码解析】【三】【体系】【BeanFactory体系】
  19. js ... es6中三个点是什么意思 真名叫扩展运算符
  20. 公司金融01.现值与贴现

热门文章

  1. 了解sentinel
  2. cisco(思科)两个不同网段相连接
  3. 新网络时代学习方式的大变革
  4. 特征值(特征向量)与相似对角化
  5. WPS中将公式居中,序号在最右边
  6. 虫师python appium自动化测试书_Selenium3自动化测试实战(基于Python语言)
  7. 如何在dw上编写php_怎么在dw打开php项目
  8. html鼠标悬停事件 dw,dw制作鼠标放上去图片就显示鼠标离开图片就消失
  9. java开发常用工具、github加速工具、idea插件
  10. element-UI 弹出外部组件