其实就是我们的一个Java实验:
TCP聊天程序。结合多线程设计方法写出聊天程序,使得可以在服务器端同时与多个客户端同时聊天。这些客户允许在不同的计算机上。
具体要求:
1) 可以多个客户使用同一套客户端代码工作,多个客户同时上线。
2)服务器总是监听客户连接请求。客户首先输入自己的姓名,再向服务器发出连接请求。当服务器监听到客户的连接请求后,服务器为该客户创建一个服务线程。双方连接成功后,客户端首先发送自己的名字给服务器,服务器收到客户名字后,向客户发送回答。然后开始双方的聊天。
3)因为服务器要同时跟多个客户聊天,所以,服务器要指定每一次的发言字符串是发给哪一个在线客户的。服务器要监测哪些客户在线。
4)当客户想结束聊天时,直接关闭聊天窗口。
我的不成熟想法:
客服端代码:
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SERVER extends JFrame implements Runnable, ActionListener {
private JButton sendMassage;
private JTextField inputmassage;
private JTextArea chatText;
private ServerSocket server = null;
private Socket socket = null;
private DataInputStream inNet = null;
private DataOutputStream outNet = null;
private Thread receiveThread;
public SERVER() {
setTitle("服务器");
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
sendMassage = new JButton("发送信息");
chatText = new JTextArea(6, 42);
inputmassage = new JTextField(16);
p2.add(inputmassage);
p2.add(sendMassage);
add(chatText, BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
sendMassage.addActionListener(this);
receiveThread = new Thread(this);
setBounds(10, 30, 650, 400);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
validate();
try {
server = new ServerSocket(8888);
chatText.append("等待客户呼叫...\n");
socket = server.accept();
inNet = new DataInputStream(socket.getInputStream());
outNet = new DataOutputStream(socket.getOutputStream());
outNet.writeUTF("您好,请问您的名字是?");
receiveThread.start();
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, "建立服务失败!");
System.exit(0);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == sendMassage) {
String msg = inputmassage.getText().trim();
if (msg.equals("")) {
JOptionPane.showMessageDialog(this, "请输入消息内容");
return;
}
try {
outNet.writeUTF("服务器: " + msg);
chatText.append("本机: " + "\n" + msg + "\n");
inputmassage.setText("");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@Override
public void run() {
try {
String msg = "";
while (true) {
msg = inNet.readUTF();
if (!msg.equals("")) {
if (getTitle().equals("服务器")) {
setTitle(msg);
outNet.writeUTF("欢迎你" + msg + "!");
} else {
chatText.append("客服: " + msg + "\n");
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main(String args[]) {
new SERVER();
}
}
客户端代码:
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CLIENT extends JFrame implements Runnable, ActionListener {
private JButton connection, sendName, sendMassage;
private JTextField inputName, inputmassage;
private JTextArea chatText;
private Socket socket = null;
private DataInputStream inNet = null;
private DataOutputStream outNet = null;
private Thread receiveThread;
private boolean connected = false;
private String name = "";
public CLIENT() {
setTitle("客户端");
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
connection = new JButton("连接服务器");
sendName = new JButton("发送姓名");
sendMassage = new JButton("发送信息");
inputName = new JTextField(8);
chatText = new JTextArea(6, 42);
inputmassage = new JTextField(16);
p1.add(new JLabel("请输入您的姓名:"));
p1.add(inputName);
p1.add(sendName);
p1.add(connection);
p2.add(inputmassage);
p2.add(sendMassage);
add(p1, BorderLayout.NORTH);
add(new JScrollPane(chatText), BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
connection.addActionListener(this);
sendName.addActionListener(this);
sendMassage.addActionListener(this);
receiveThread = new Thread(this);
setBounds(10, 30, 650, 400);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
validate();
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == connection) {
if (!connected) {
try {
socket = new Socket("127.0.0.1", 8888);
inNet = new DataInputStream(socket.getInputStream());
outNet = new DataOutputStream(socket.getOutputStream());
connection.setText("断开连接");
connected = true;
chatText.append("成功连接服务器\n");
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, "连接服务器失败");
}
} else {
try {
socket.close();
inNet.close();
outNet.close();
connection.setText("连接服务器");
connected = false;
sendName.setEnabled(false);
sendMassage.setEnabled(false);
chatText.append("成功断开与服务器的连接\n");
} catch (IOException ex) {
ex.printStackTrace();
}
}
} else if (e.getSource() == sendName) {
if (name.equals("")) {
name = inputName.getText();
if (name.equals("")) {
JOptionPane.showMessageDialog(this, "请先输入姓名");
return;
}
inputName.setEditable(false);
sendName.setEnabled(false);
sendMassage.setEnabled(true);
try {
outNet.writeUTF(name);
chatText.append("成功发送姓名\n");
} catch (IOException ex) {
ex.printStackTrace();
}
}
} else if (e.getSource() == sendMassage) {
String msg = inputmassage.getText().trim();
if (msg.equals("")) {
JOptionPane.showMessageDialog(this, "请输入消息内容");
return;
}
try {
outNet.writeUTF(msg);
chatText.append(name +"\n" + ": " + msg + "\n");
inputmassage.setText("");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@Override
public void run() {
while (true) {
try {
String msg = inNet.readUTF();
if (!msg.equals("")) {
if (name.equals("")) {
name = msg;
chatText.append("欢迎你!" + "\n" + name + "!\n");
sendName.setEnabled(false);
sendMassage.setEnabled(true);
} else {
chatText.append("客服: " + "\n" + msg + "\n");
}
}
} catch (IOException ex) {
ex.printStackTrace();
break;
}
}
}
public static void main(String args[]) {
new CLIENT();
}
}
运行结果其实还好,有以下几个优点:
1:要求一都实现了。
2:没创建线程,本来是想在客服端加上“一个客户创建一个线程,创建一个窗口”功能,但是没实现成功
3:要求三超额完成,不仅只能单独聊天,而且还只能单向发送。
4:要求四完成了, 还在客户端连接服务器后未关闭服务器端就关闭客户端时附赠了报错大礼包:
以下是大体运行结果,错误都写在里面了(消息格式可以不用在意):