java模拟简单的qq聊天_初学java之模拟QQ聊天软件(简单实现)

引言:这个程序是自从学习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所示:

123006730_1_20180125055657128

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

————————————–所有的源代码————————————–

3详细设计及实现

3.1服务器端

3.1.1服务器主类ChatRoomServerMain

package server;

public class ChatRoomServerMain

{

/**

* @author CSJ

*/

public static void main(String[] args)

{

new ChatRoomServerFrame();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

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 userMap;

private Set 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();

userSet = new HashSet();

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()

{

@Override

public void actionPerformed(ActionEvent arg0)

{

try

{

serverSocket = new ServerSocket(9000);

new Thread(new Runnable()

{

@Override

public void run()

{

startServer();

}

}).start();

JOptionPane.showMessageDialog(null, "服务器已启动!");

} catch (IOException e)

{

JOptionPane.showMessageDialog(null, "服务器已启动!");

e.printStackTrace();

}

}

});

addWindowListener(new WindowAdapter()

{

@Override

public 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();

}

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

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 userSet;

private Map userMap;

private StringBuffer userList;

private JTextArea hintInfo;

private JTextArea startInfoTextArea;

private JTextArea onlineUserInfo;

public ChatRoomServerThread(ServerClientConnectionStream userCS, Set userSet,

Map 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();

}

@Override

public 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();

}

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

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;

// 姓名 账户 IP

public 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);

}

@Override

public 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()

{

@Override

public 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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

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 currentOnlineUserList;

private Map userInfoMap;

private DatagramSocket dataSocket;

private UserInformation userInfo;

private ReadMessageFromServerThread readMessageFromServerThread;

private Thread readMessagehread;

private ChatRoomClientFrame chatRoomClientFrame;

private Map chatRoomMap = new HashMap();

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();

try

{

dataSocket = new DatagramSocket(userInfo.getPort());

} catch (SocketException e)

{

e.printStackTrace();

}

}

private void createFrame()

{

currentOnlineUserList = new JList();

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()

{

@Override

public 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()

{

@Override

public 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()

{

@Override

public 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();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

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 端口号 姓名 账号 密码

@Override

public 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()

{

@Override

public 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()

{

@Override

public void mouseClicked(MouseEvent e)

{

JOptionPane.showMessageDialog(null, "本功能暂未开放!");

}

@Override

public void mouseEntered(MouseEvent e)

{

}

@Override

public void mouseExited(MouseEvent e)

{

}

@Override

public void mousePressed(MouseEvent e)

{

}

@Override

public void mouseReleased(MouseEvent e)

{

}

});

findPassword.addMouseListener(new MouseListener()

{

@Override

public void mouseReleased(MouseEvent e)

{

}

@Override

public void mousePressed(MouseEvent e)

{

}

@Override

public void mouseExited(MouseEvent e)

{

}

@Override

public void mouseEntered(MouseEvent e)

{

}

@Override

public void mouseClicked(MouseEvent e)

{

JOptionPane.showMessageDialog(null, "本功能暂未开放!");

}

});

remPassword.addActionListener(new ActionListener()

{

@Override

public void actionPerformed(ActionEvent e)

{

JOptionPane.showMessageDialog(null, "本功能暂未开放!");

}

});

autoLogin.addActionListener(new ActionListener()

{

@Override

public void actionPerformed(ActionEvent e)

{

JOptionPane.showMessageDialog(null, "本功能暂未开放!");

}

});

addWindowListener(new WindowAdapter()

{

@Override

public void windowClosing(WindowEvent e)

{

System.exit(0);

}

});

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

3.2.4客户端登陆主类LoginMain

package client;

public class LoginMain

{

/**

* @author CSJ

*/

public static void main(String[] args)

{

new LoginFrame();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

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);

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

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;

}

@Override

public 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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

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 currentOnlineUserList;

private volatile boolean stop = false;

private MyMap isOpenMap;

private Map userInfoMap;

private String loginName;

public ReadMessageFromServerThread(ServerClientConnectionStream userCS,

Map userInfoMap, JList 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);

}

@Override

public 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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

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 myMap;

public MyMap()

{

super();

myMap = new HashMap();

}

public MyMap(String key, boolean value)

{

super();

myMap = new HashMap();

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 getIsOnlineMap()

{

return myMap;

}

public void setIsOnlineMap(Map 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);

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

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;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

5测试

123006730_2_20180125055657253

图5-1 服务器界面

123006730_3_20180125055657378

图5-2服务器启动界面

123006730_4_20180125055657503

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

123006730_5_20180125055657612

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

123006730_6_20180125055657721

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

123006730_7_20180125055657909

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

123006730_8_2018012505565818

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

123006730_9_20180125055658159

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

123006730_10_20180125055658237

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

123006730_11_20180125055658331

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

123006730_12_20180125055658456

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

123006730_13_20180125055658565

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

123006730_14_20180125055658690

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

123006730_15_20180125055658784

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

123006730_16_20180125055658940

图5-15当前的三个用户

123006730_17_20180125055659128

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

123006730_18_20180125055659300

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

123006730_19_20180125055659456

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

123006730_20_20180125055659721

图5-19 聊天截图

123006730_21_2018012505570096

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

123006730_22_20180125055700300

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

123006730_23_20180125055700471

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

123006730_24_20180125055700659

图5-23 聊天截图

123006730_25_2018012505570118

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

123006730_26_20180125055701159

123006730_27_20180125055701753

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

6结束语

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

参考文献

 赵新慧 等. Java程序设计教程,清华大学出版社,2014

 网络编程相关资料

电子文档:

第11章 网络编程.ppt

JDK_API_1_6_zh_CN.CHM

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现模拟QQ登录的功能,你需要编写以下代码: ```java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class QQLogin extends JFrame implements ActionListener { private JTextField userField = new JTextField(20); private JPasswordField passField = new JPasswordField(20); public QQLogin() { // 设置窗口标题 setTitle("QQ登录"); // 创建用户标签和文本框 JLabel userLabel = new JLabel("用户名:"); JPanel userPanel = new JPanel(); userPanel.add(userLabel); userPanel.add(userField); // 创建密码标签和文本框 JLabel passLabel = new JLabel("密 码:"); JPanel passPanel = new JPanel(); passPanel.add(passLabel); passPanel.add(passField); // 创建登录和取消按钮 JButton loginButton = new JButton("登录"); loginButton.addActionListener(this); JButton cancelButton = new JButton("取消"); cancelButton.addActionListener(this); JPanel buttonPanel = new JPanel(); buttonPanel.add(loginButton); buttonPanel.add(cancelButton); // 添加组件到窗口 setLayout(new GridLayout(3, 1)); add(userPanel); add(passPanel); add(buttonPanel); // 设置窗口大小 setSize(300, 150); // 显示窗口 setVisible(true); } @Override public void actionPerformed(ActionEvent e) { // 处理登录和取消按钮事件 if (e.getActionCommand().equals("登录")) { String user = userField.getText(); String pass = new String(passField.getPassword()); if (user.equals("admin") && pass.equals("123456")) { JOptionPane.showMessageDialog(this, "登录成功!"); } else { JOptionPane.showMessageDialog(this, "用户名或密码错误,请重新输入!"); } } else if (e.getActionCommand().equals("取消")) { System.exit(0); } } public static void main(String[] args) { new QQLogin(); } } ``` 这段代码创建了一个QQ登录窗口,并添加了用户名、密码、登录和取消按钮。当用户输入正确的用户名和密码并点击登录按钮时,会弹出一个对话框提示登录成功;否则会弹出一个对话框提示用户名或密码错误。当用户点击取消按钮时,程序会退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值