具体流程:
启动服务器——监听端口——等待客户端的连接——启动客户端1和2与服务器进行TCP连接——客户端左边窗口为与客户端的通信,
右边窗口为与另一客户端的通信——服务器监听得到客户端两方的IP与端口——服务器将客户端彼此的IP与端口发送到对方——客户端获得对方IP与端口后进行UDP连接——连接完成,三方可进行通信。
client1.java
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class client1 extends JFrame
{
//UI界面需要组件
private JTextField enter; // 创建文本框
private JTextArea display; // 创建显示文本域
private JTextField enter2; // 创建文本框
private JTextArea display2; // 创建显示文本域
private JLabel tcpLabel=new JLabel("与服务器连接");
private JLabel udpLabel=new JLabel("与另一客户端连接");
//Tcp需要的变量
PrintStream output; // 输出流
BufferedReader input; // 输入流
String message = "";
//Udp需要的变量
DatagramSocket ds;
InetAddress address;
byte[] buf=new byte[1024];
DatagramPacket dp;
String strInfo="";
String[] mess;
String str="";
int port;
public client1()
{
super("client1");
Container c = getContentPane();
c.setLayout(null);
JPanel c1=new JPanel();
JPanel c2=new JPanel();
c1.setLayout(new BorderLayout());
c2.setLayout(new BorderLayout());
enter = new JTextField(); // 创建文本框对象
enter.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData(enter.getText());
} // 提取文本框中的内容
});
c1.add(enter, BorderLayout.NORTH); // 将文本区域添加到容器的上方
display = new JTextArea(); // 创建显示文本域
c1.add(new JScrollPane(display), BorderLayout.CENTER);// 添加带有滚动条的文本域到容器的中央
c1.add(tcpLabel, BorderLayout.SOUTH);
c1.setBounds(0, 0, 250, 300);
enter2 = new JTextField(); // 创建文本框对象
enter2.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData2(enter2.getText());
}
});
c2.add(enter2, BorderLayout.NORTH);
display2 = new JTextArea();
c2.add(new JScrollPane(display2), BorderLayout.CENTER);
c2.add(udpLabel, BorderLayout.SOUTH);
c2.setBounds(250, 0, 250, 300);
add(c1);
add(c2);
setSize(505, 350);
setVisible(true);
}
public void connect() { //与服务器的连接
Socket socket; // 创建客户端的Socket对象
try {
// 第1步:与服务器端创建连接,地址是127.0.0.1,端口为4321
display.setText("准备连接...\n");
System.out.println(InetAddress.getByName(""));
socket = new Socket("127.0.0.1", 4321);
display.append("连接到:" + socket.getInetAddress().getHostName());
// 获得主机名
display.append("\n主机IP为:" + socket.getInetAddress().toString());
// 获得主机IP地址
// 第2步:获得输出/输入流
output = new PrintStream(new BufferedOutputStream(socket
.getOutputStream()));
output.flush();
input = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 第3步:实现连接,读入服务器的信息
do {
try {
message = (String) input.readLine();
// 读入输入流的内容,也就是服务器端PrintStream缓冲区中传递的信息
display.append("\n" + message); // 将读入的内容添加到文本域中
display.setCaretPosition(display.getText().length());//使到滚动条自动下滚
if(message.startsWith("另一客户端IP与端口"))
{
mess=message.split(":");
try {
ds = new DatagramSocket(socket.getLocalPort());
address = InetAddress.getByName(mess[1]);
port=Integer.parseInt(mess[2]);
dp=new DatagramPacket(buf, 1024);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
}
new connect2().start();
sendData2("建立连接");
}
} catch (IOException e) {
display.append("\n无法获得信息");
}
} while (!message.equals("Server: end")); // 当服务器端输入"end"时,通信结束
// 第4步:关闭连接
display.append("\n关闭连接");
output.close();
input.close();
socket.close();
} catch (EOFException eof) {
System.out.println("服务器中断连接");
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendData(String s)
{ // 此子程序的功能是向服务器端传递信息
try {
message = s;
output.println("Client1: " + s); // 将文本框中的内容发送PrintStream缓冲区中
output.flush();
enter.setText("");
} catch (Exception e) {
display.append("\n数据传输错误!");
}
}
private void sendData2(String s)
{
str="";
str="Client1: "+s;
try {
ds.send(new DatagramPacket(str.getBytes(), str.getBytes().length,address, port));
} catch (IOException e) {
e.printStackTrace();
}
enter2.setText("");
}
public static void main(String[] args)
{
client1 clie1=new client1();
clie1.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
clie1.connect();
}
class connect2 extends Thread
{
@Override
public void run()
{
connect2();
}
public void connect2() //与另一客户端的连接
{
do {
try {
ds.receive(dp);
strInfo = new String(dp.getData(), 0, dp.getLength());
if(strInfo.equals("")||strInfo.equals("Client2: end"))
{
continue;
}
else
{
display2.append("\n" + strInfo);
display2.setCaretPosition(display2.getText().length());//使到滚动条自动下滚
strInfo="";
}
} catch (IOException e) {
e.printStackTrace();
}
} while (!strInfo.substring(strInfo.indexOf(":")+1, strInfo.length()).equals(" end"));
ds.close();
}
}
}
client2.java
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class client2 extends JFrame
{
//UI界面需要组件
private JTextField enter; // 创建文本框
private JTextArea display; // 创建显示文本域
private JTextField enter2; // 创建文本框
private JTextArea display2; // 创建显示文本域
private JLabel tcpLabel=new JLabel("与服务器连接");
private JLabel udpLabel=new JLabel("与另一客户端连接");
//Tcp需要的变量
PrintStream output; // 输出流
BufferedReader input; // 输入流
String message = "";
//Udp需要的变量
DatagramSocket ds;
InetAddress address;
byte[] buf=new byte[1024];
DatagramPacket dp;
String strInfo="";
String[] mess;
String str="";
int port;
public client2()
{
super("client2");
Container c = getContentPane();
c.setLayout(null);
JPanel c1=new JPanel();
JPanel c2=new JPanel();
c1.setLayout(new BorderLayout());
c2.setLayout(new BorderLayout());
enter = new JTextField(); // 创建文本框对象
enter.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData(enter.getText());
} // 提取文本框中的内容
});
c1.add(enter, BorderLayout.NORTH); // 将文本区域添加到容器的上方
display = new JTextArea(); // 创建显示文本域
c1.add(new JScrollPane(display), BorderLayout.CENTER);// 添加带有滚动条的文本域到容器的中央
c1.add(tcpLabel, BorderLayout.SOUTH);
c1.setBounds(0, 0, 250, 300);
enter2 = new JTextField(); // 创建文本框对象
enter2.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData2(enter2.getText());
}
});
c2.add(enter2, BorderLayout.NORTH);
display2 = new JTextArea();
c2.add(new JScrollPane(display2), BorderLayout.CENTER);
c2.add(udpLabel, BorderLayout.SOUTH);
c2.setBounds(250, 0, 250, 300);
add(c1);
add(c2);
setSize(505, 350);
setVisible(true);
}
public void connect() { //与服务器的连接
Socket socket; // 创建客户端的Socket对象
try {
// 第1步:与服务器端创建连接,地址是127.0.0.1,端口为4321
display.setText("准备连接...\n");
System.out.println(InetAddress.getByName(""));
socket = new Socket(InetAddress.getByName(""), 4321);
// socket=new Socket("127.0.0.1",4321);
display.append("连接到:" + socket.getInetAddress().getHostName());
// 获得主机名
display.append("\n主机IP为:" + socket.getInetAddress().toString());
// 获得主机IP地址
// 第2步:获得输出/输入流
output = new PrintStream(new BufferedOutputStream(socket
.getOutputStream()));
output.flush();
input = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 第3步:实现连接,读入服务器的信息
do {
try {
message = (String) input.readLine();
// 读入输入流的内容,也就是服务器端PrintStream缓冲区中传递的信息
display.append("\n" + message); // 将读入的内容添加到文本域中
display.setCaretPosition(display.getText().length());//使到滚动条自动下滚
if(message.startsWith("另一客户端IP与端口"))
{
mess=message.split(":");
try {
ds = new DatagramSocket(socket.getLocalPort());
address = InetAddress.getByName(mess[1]);
port=Integer.parseInt(mess[2]);
dp=new DatagramPacket(buf, 1024);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
}
new connect2().start();
sendData2("建立连接");
}
} catch (IOException e) {
display.append("\n无法获得信息");
}
} while (!message.equals("Server: end")); // 当服务器端输入"end"时,通信结束
// 第4步:关闭连接
display.append("\n关闭连接");
output.close();
input.close();
socket.close();
} catch (EOFException eof) {
System.out.println("服务器中断连接");
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendData(String s)
{ // 此子程序的功能是向服务器端传递信息
try {
message = s;
output.println("Client2: " + s); // 将文本框中的内容发送PrintStream缓冲区中
output.flush();
enter.setText("");
} catch (Exception e) {
display.append("\n数据传输错误!");
}
}
private void sendData2(String s)
{
str="";
str="Client2: "+s;
try {
ds.send(new DatagramPacket(str.getBytes(), str.getBytes().length,address, port));
} catch (IOException e) {
e.printStackTrace();
}
enter2.setText("");
}
public static void main(String[] args)
{
client2 clie2=new client2();
clie2.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
clie2.connect();
}
class connect2 extends Thread
{
@Override
public void run()
{
connect2();
}
public void connect2() //与另一客户端的连接
{
do {
try {
ds.receive(dp);
strInfo = new String(dp.getData(), 0, dp.getLength());
if(strInfo.equals("")||strInfo.equals("Client1: end"))
{
continue;
}
else
{
display2.append("\n" + strInfo);
display2.setCaretPosition(display2.getText().length());//使到滚动条自动下滚
strInfo="";
}
} catch (IOException e) {
e.printStackTrace();
}
} while (!strInfo.substring(strInfo.indexOf(":")+1, strInfo.length()).equals(" end"));
ds.close();
}
}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class client2 extends JFrame
{
//UI界面需要组件
private JTextField enter; // 创建文本框
private JTextArea display; // 创建显示文本域
private JTextField enter2; // 创建文本框
private JTextArea display2; // 创建显示文本域
private JLabel tcpLabel=new JLabel("与服务器连接");
private JLabel udpLabel=new JLabel("与另一客户端连接");
//Tcp需要的变量
PrintStream output; // 输出流
BufferedReader input; // 输入流
String message = "";
//Udp需要的变量
DatagramSocket ds;
InetAddress address;
byte[] buf=new byte[1024];
DatagramPacket dp;
String strInfo="";
String[] mess;
String str="";
int port;
public client2()
{
super("client2");
Container c = getContentPane();
c.setLayout(null);
JPanel c1=new JPanel();
JPanel c2=new JPanel();
c1.setLayout(new BorderLayout());
c2.setLayout(new BorderLayout());
enter = new JTextField(); // 创建文本框对象
enter.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData(enter.getText());
} // 提取文本框中的内容
});
c1.add(enter, BorderLayout.NORTH); // 将文本区域添加到容器的上方
display = new JTextArea(); // 创建显示文本域
c1.add(new JScrollPane(display), BorderLayout.CENTER);// 添加带有滚动条的文本域到容器的中央
c1.add(tcpLabel, BorderLayout.SOUTH);
c1.setBounds(0, 0, 250, 300);
enter2 = new JTextField(); // 创建文本框对象
enter2.addActionListener(new ActionListener() { // 对文本区域添加监听
public void actionPerformed(ActionEvent e) {
sendData2(enter2.getText());
}
});
c2.add(enter2, BorderLayout.NORTH);
display2 = new JTextArea();
c2.add(new JScrollPane(display2), BorderLayout.CENTER);
c2.add(udpLabel, BorderLayout.SOUTH);
c2.setBounds(250, 0, 250, 300);
add(c1);
add(c2);
setSize(505, 350);
setVisible(true);
}
public void connect() { //与服务器的连接
Socket socket; // 创建客户端的Socket对象
try {
// 第1步:与服务器端创建连接,地址是127.0.0.1,端口为4321
display.setText("准备连接...\n");
System.out.println(InetAddress.getByName(""));
socket = new Socket(InetAddress.getByName(""), 4321);
// socket=new Socket("127.0.0.1",4321);
display.append("连接到:" + socket.getInetAddress().getHostName());
// 获得主机名
display.append("\n主机IP为:" + socket.getInetAddress().toString());
// 获得主机IP地址
// 第2步:获得输出/输入流
output = new PrintStream(new BufferedOutputStream(socket
.getOutputStream()));
output.flush();
input = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 第3步:实现连接,读入服务器的信息
do {
try {
message = (String) input.readLine();
// 读入输入流的内容,也就是服务器端PrintStream缓冲区中传递的信息
display.append("\n" + message); // 将读入的内容添加到文本域中
display.setCaretPosition(display.getText().length());//使到滚动条自动下滚
if(message.startsWith("另一客户端IP与端口"))
{
mess=message.split(":");
try {
ds = new DatagramSocket(socket.getLocalPort());
address = InetAddress.getByName(mess[1]);
port=Integer.parseInt(mess[2]);
dp=new DatagramPacket(buf, 1024);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
}
new connect2().start();
sendData2("建立连接");
}
} catch (IOException e) {
display.append("\n无法获得信息");
}
} while (!message.equals("Server: end")); // 当服务器端输入"end"时,通信结束
// 第4步:关闭连接
display.append("\n关闭连接");
output.close();
input.close();
socket.close();
} catch (EOFException eof) {
System.out.println("服务器中断连接");
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendData(String s)
{ // 此子程序的功能是向服务器端传递信息
try {
message = s;
output.println("Client2: " + s); // 将文本框中的内容发送PrintStream缓冲区中
output.flush();
enter.setText("");
} catch (Exception e) {
display.append("\n数据传输错误!");
}
}
private void sendData2(String s)
{
str="";
str="Client2: "+s;
try {
ds.send(new DatagramPacket(str.getBytes(), str.getBytes().length,address, port));
} catch (IOException e) {
e.printStackTrace();
}
enter2.setText("");
}
public static void main(String[] args)
{
client2 clie2=new client2();
clie2.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
clie2.connect();
}
class connect2 extends Thread
{
@Override
public void run()
{
connect2();
}
public void connect2() //与另一客户端的连接
{
do {
try {
ds.receive(dp);
strInfo = new String(dp.getData(), 0, dp.getLength());
if(strInfo.equals("")||strInfo.equals("Client1: end"))
{
continue;
}
else
{
display2.append("\n" + strInfo);
display2.setCaretPosition(display2.getText().length());//使到滚动条自动下滚
strInfo="";
}
} catch (IOException e) {
e.printStackTrace();
}
} while (!strInfo.substring(strInfo.indexOf(":")+1, strInfo.length()).equals(" end"));
ds.close();
}
}
}
server.java
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class server extends JFrame {
private JTextField enter; // 创建文本框
private JTextArea display; // 创建显示文本域
PrintStream[] output=new PrintStream[10]; // 输出流
BufferedReader[] input=new BufferedReader[10];
String message;// 输入流
Socket[] socket=new Socket[10]; // 客户端的Socket接口对象
int counter = 1; // 连接数
public server() {
super("Server"); // 引用父类的超类
Container c = getContentPane();
enter = new JTextField(); // 创建文本框对象
enter.setEnabled(false); // 文本框不可编辑
enter.addActionListener(new ActionListener() { // 为文本框加入事件监听
public void actionPerformed(ActionEvent e) {
sendData(enter.getText());
} // 将输入到文本框中的字符发送到客户端
});
c.add(enter, BorderLayout.NORTH); // 定义文本框在容器中的位置
display = new JTextArea(); // 创建文本域对象
c.add(new JScrollPane(display), BorderLayout.CENTER);
setSize(300, 300);
setVisible(true);
}
private void sendData(String s)
{ // 将文本框中的字符传递给客户端
try {
for(int i=1;i<=counter;i++)
{
output[i].println("Server: " + s); // 将文本框中的内容发送到PrintStream缓冲区中
output[i].flush(); // 将缓冲区中的数据发送到客户端
enter.setText(""); // 设置文本框的内容为“空”
}
} catch (Exception e) {
}
}
public void connect() {
ServerSocket server; // 服务器端的Socket接口对象
try {
// 第1步:创建一个监听,端口是4321,最大连接数是10
server = new ServerSocket(4321, 10);
while (true)
{
// 第1步:等待一个请求
display.append("等待客户端的请求\n");
socket[counter] = server.accept(); // 等待客户端的请求
display.append("连接" + counter + "来自:"
+ socket[counter].getInetAddress().getHostName()
+"\n对方端口为"+socket[counter].getPort()+"\n");
// 第3步:获得输入和输出流
output[counter] = new PrintStream(new BufferedOutputStream(
socket[counter].getOutputStream()));
output[counter].flush();
input[counter]= new BufferedReader(new InputStreamReader(
socket[counter].getInputStream()));
// 第4步:传递信息
message = "Server Connection successful!";
output[counter].println(message); // 将“message”字符串内容发送到PrintStream缓冲区中
output[counter].flush(); // 将缓冲区中的数据发送到客户端
enter.setEnabled(true);
ser ser=new ser(socket[counter],input[counter],output[counter]);
ser.start();
if(counter==2)
{
output[1].println("另一客户端IP与端口:" + socket[2].getInetAddress().getHostAddress()
+":"+socket[2].getPort());
output[1].flush();
output[2].println("另一客户端IP与端口:" + socket[1].getInetAddress().getHostAddress()
+":"+socket[1].getPort());
output[2].flush();
}
++counter;
}
} catch (EOFException eof) {
System.out.println("Client terminated connection");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
server app = new server();
app.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
app.connect();
}
//多线程内部类,处理多个客户端
class ser extends Thread
{
Socket socket;
BufferedReader input;
PrintStream output;
public ser(Socket socket, BufferedReader input,PrintStream output)
{
this.socket=socket;
this.input=input;
this.output=output;
}
@Override
public void run()
{
try {
do{
message = (String) input.readLine();
display.append("\n" + message); // 在文本域显示客户端传递的信息
display.setCaretPosition(display.getText().length());//使到滚动条自动下滚
} while (!message.substring(message.indexOf(":")+1, message.length()).equals(" end"));
// 第5步:拆除连接
display.append("\n关闭连接");
output.close();
input.close();
socket.close(); // 关闭当前客户端请求,继续监听其他客户端
} catch (IOException e) {
display.append("Data Error");
}
}
}
}