第一版本:
实现一个简单的聊天窗口:
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ChatClient1 extends JFrame {
public void launch() {
this.setVisible(true);
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
}
public static void main(String[] args) {
new ChatClient1().launch();
}
}
第二版本:
添加一个输入文字,以及显示文字的地方;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ChatClient2 extends JFrame {
private JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
ta.setBackground(Color.GRAY);
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
}
public static void main(String[] args) {
new ChatClient2().launch();
}
}
第三版本:
从JTextField输入框输入文字,敲击回车键,让文字显示到JTextArea
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ChatClient2 extends JFrame {
private JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.GRAY);
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
ta.append(tf.getText().trim() +"\n");
tf.setText("");
}
});
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
}
public static void main(String[] args) {
new ChatClient2().launch();
}
}
第四版本:
此版本实现客户端与服务器端的链接;
客户端:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import Chat3.ChatClient3;
public class ChatClient5 extends JFrame {
private JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
private JScrollPane js = new JScrollPane(ta, 4, 4);
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.GRAY);
tf.addActionListener(new MyTFMonitor());
this.add(tf, BorderLayout.SOUTH);
this.add(js, BorderLayout.CENTER);
}
private class MyTFMonitor implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
ta.append(tf.getText().trim() +"\n");
tf.setText("");
}
}
public static void main(String[] args) {
new ChatClient3().launch();
try {
Socket s = new Socket("127.0.0.1", 8888);
} catch(IOException e) {
e.printStackTrace();
}
}
}
服务器端:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatServer1 {
public static void main(String[] args) {
ServerSocket ss;
try {
ss = new ServerSocket(8888);
while(true) {
Socket s = ss.accept();
System.out.println("a client connected!");
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
第五版本:
此版本实现了将一个客户端连接到服务器上然后发送消息给服务器知道输入bye是客户端Socket自动断开,
此时JFrame并没有消失,若此时想JTextField输入信息并按下回车键,则会发生java.net.SocketException;
此时的服务器端已接收不到来自刚刚客户端的消息,但是他仍然在等待着其他客户端的连接。
客户端:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import Chat3.ChatClient3;
public class ChatClient6 extends JFrame {
public Socket s;
public DataOutputStream dos;
public DataInputStream dis;
public JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.LIGHT_GRAY);
tf.addActionListener(new MyTFMonitor());
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
connected();
}
private class MyTFMonitor implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
try {
String str = tf.getText();
ta.append(str.trim() +"\n");
dos.writeUTF(str);
tf.setText("");
if(str.equalsIgnoreCase("bye")) {
fclose();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
public void connected() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
dos = new DataOutputStream(os);
dis = new DataInputStream(is);
} catch(IOException e) {
e.printStackTrace();
}
}
public void fclose() {
try {
dos.flush();
dos.close();
dis.close();
} catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ChatClient6().launch();
}
}
服务器端:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatServer2 {
public static void main(String[] args) {
ServerSocket ss;
try {
ss = new ServerSocket(8888);
while(true) {
Socket s = ss.accept();
System.out.println("a client connected!");
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
DataOutputStream dos = new DataOutputStream(os);
DataInputStream dis = new DataInputStream(is);
while(true) {
String str = dis.readUTF();
System.out.println(str);
if(str.equalsIgnoreCase("bye")) {
break;
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
第六版本:
经过修改之后只要输入bye之后,客户端的JFrame将会自动关闭,不再会产生java.net.SocketException;
如何修改,在关闭客户端与服务器端的输入输出通道时关闭JFrame,即setVisiable(false),
之后关闭程序,即System.exit(-1);
如果客户端因断电,断网等无法控制因素导致客户端关闭时,Server端会将于客户端建立的输入输出流以及Socket关闭掉,
但是ServerSocket仍然等待其他客户端的连接。
当已经有一个服务器程序在运行,但是又启动了一个,此时只能提示用户相关信息,
并使已经在运行的程序退出System.exit(-1);
服务器端:
package Chat7;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatServer3 {
public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
try {
ss = new ServerSocket(8888);
} catch(BindException e2) {
System.out.println("端口已被使用!");
System.out.println("请关闭相关程序并重新运行服务器!");
System.exit(-1);
} catch(IOException e3) {
e3.printStackTrace();
}
while(true) {
try {
s = ss.accept();
System.out.println("a client connected!");
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
while(true) {
String str = dis.readUTF();
System.out.println(str);
if(str.equalsIgnoreCase("bye")) {
try {
s.close();
dos.close();
dis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
} catch(EOFException e) {
System.out.println("client closed!");
} catch(IOException e1) {
e1.printStackTrace();
} finally {
try {
if(s != null ||
dos != null ||
dis != null) {
s.close();
dos.close();
dis.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
客户端:
package Chat7;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import Chat3.ChatClient3;
public class ChatClient7 extends JFrame {
public Socket s;
public DataOutputStream dos;
public DataInputStream dis;
public JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.LIGHT_GRAY);
tf.addActionListener(new MyTFMonitor());
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
connected();
}
private class MyTFMonitor implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
try {
String str = tf.getText();
ta.append(str.trim() +"\n");
dos.writeUTF(str);
tf.setText("");
if(str.equalsIgnoreCase("bye")) {
fclose();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
public void connected() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
} catch(IOException e) {
e.printStackTrace();
}
}
public void fclose() {
try {
dos.flush();
dos.close();
if(dis == null) {
dis.close();
}
this.setVisible(false);
System.exit(-1);
} catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ChatClient7().launch();
}
}
第七版本:
此版本是实现多个客户端往同一个服务器端连接,一开始的问题是:
只能实现一个客户端的连接,下一个连接只能等这个客户端断开连接了才能练上来。
解决这种问题的方法是有两种:
一:
异步
二:
线程
1:如何选择内部类,外部类,匿名类
匿名类一般不考虑,内部类是这样考虑的:你这个类是否需要外边的泪服务,如果要的话就用外部类,
如果只是自己用的话内部类就可以了。
2:主线程只干一件事,连接客户端,美连接一个客户端就启一个线程,去单独的处理它。
服务器端:
package Chat8;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class ChatServer5 {
ServerSocket ss = null;
public ChatServer5() {
try {
ss = new ServerSocket(8888);
} catch (IOException e) {
e.printStackTrace();
}
}
public void connectedStart() {
Socket s = null;
try {
s = ss.accept();
System.out.println("A client connected!");
} catch (IOException e) {
e.printStackTrace();
}
new Thread(new Client(s)).start();
}
public static void main(String[] args) {
ChatServer5 cs = new ChatServer5();
while(true) {
cs.connectedStart(); //静态的方法中不允许有非静态的对象出现
}
}
class Client implements Runnable {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
public Client(Socket s) {
this.s = s;
}
public void run() {
try {
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
String str = null;
try {
str = dis.readUTF();
//下面的两个catch不能颠倒顺序,因为如果你把所有的IOException逮到,
//那就连SocketExcdption也就逮到了,所以不能调换顺序
} catch(SocketException se) {
System.out.println("Client is not cliented!");
//break是当客户端因某些原因被迫没有告知服务器端就结束时(断电等),
//则直接break让服务器端直接等待下一个客户端的连接
break;
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(str);
if(str.equalsIgnoreCase("bye".trim())) {
try {
s.close();
dos.close();
dis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
}
}
}
客户端:
package Chat8;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import Chat3.ChatClient3;
public class ChatClient8 extends JFrame {
public Socket s;
public DataOutputStream dos;
public DataInputStream dis;
public JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.LIGHT_GRAY);
tf.addActionListener(new MyTFMonitor());
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
connected();
}
private class MyTFMonitor implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
try {
String str = tf.getText();
ta.append(str.trim() +"\n");
dos.writeUTF(str);
tf.setText("");
if(str.equalsIgnoreCase("bye".trim())) {
fclose();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
public void connected() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
} catch(IOException e) {
e.printStackTrace();
}
}
public void fclose() {
try {
dos.flush();
dos.close();
if(dis == null) {
dis.close();
}
this.setVisible(false);
System.exit(-1);
} catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ChatClient8().launch();
}
}
第八版本:
本版本实现的时服务器吧接受的消息给每个客户端发过去
服务器端:
package Chat9;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
public class ChatServer6 {
List<Client> l = new <Client>ArrayList();
ServerSocket ss = null;
public ChatServer6() {
try {
ss = new ServerSocket(8888);
} catch (IOException e) {
e.printStackTrace();
}
}
public void connectedStart() {
Socket s = null;
try {
s = ss.accept();
System.out.println("A client connected!");
} catch (IOException e) {
e.printStackTrace();
}
Client c = new Client(s);
l.add(c);
new Thread(c).start();
}
class Client implements Runnable {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
public Client(Socket s) {
this.s = s;
}
public void run() {
try {
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
while(true) {
String str = null;
try {
str = dis.readUTF();
for(int i=0; i<l.size(); i++) {
Client c = l.get(i);
c.send(str);
}
} catch(SocketException se) {
System.out.println("Client is not cliented!");
break;
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(str);
if(str.equalsIgnoreCase("bye".trim())) {
try {
s.close();
dos.close();
dis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(dos!=null) {
dos.close();
l.remove(this);
}
if(dis!=null) {
dis.close();
}
if(s!=null) {
s.close();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
public void send(String str) {
try {
dos.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ChatServer6 cs = new ChatServer6();
while(true) {
cs.connectedStart(); //静态的方法中不允许有非静态的对象出现
}
}
}
客户端:
package Chat9;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import Chat3.ChatClient3;
public class ChatClient9 extends JFrame {
public Socket s;
public boolean bConnected = false;
public DataOutputStream dos;
public DataInputStream dis;
public JTextField tf = new JTextField();
private JTextArea ta = new JTextArea();
public void launch() {
this.setVisible(true);
this.pack();
this.setLocation(500, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 500);
this.setLayout(new BorderLayout());
ta.setBackground(Color.LIGHT_GRAY);
tf.addActionListener(new MyTFMonitor());
this.add(tf, BorderLayout.SOUTH);
this.add(ta, BorderLayout.CENTER);
connected();
new Thread(new RecvThread()).start();
}
private class MyTFMonitor implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
try {
String str = tf.getText();
dos.writeUTF(str);
tf.setText("");
if(str.equalsIgnoreCase("bye".trim())) {
fclose();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
public void connected() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
bConnected = true;
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
} catch(IOException e) {
e.printStackTrace();
}
}
public void fclose() {
try {
dos.flush();
dos.close();
if(dis == null) {
dis.close();
}
this.setVisible(false);
System.exit(-1);
} catch(IOException e) {
e.printStackTrace();
}
}
private class RecvThread implements Runnable {
public void run() {
try {
while(bConnected) {
String s = dis.readUTF();
ta.setText(ta.getText() + '\n' + s);
}
} catch(SocketException e1) {
System.out.println("Another client is closed!");
} catch(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ChatClient9().launch();
}
}
上面的第八版本也就是最后的版本