java TCP与UDP通信

    该程序只是较为简单的实现了java网络编程中TCP通信与UDP通信的原理,java文件中,server为服务器程序client1与client2均为客户端程序(代码基本上是一样的)。程序中,server作为服务器,监听端口,等待客户端的连接,实现的是,一旦有两个客户端连接到服务器,服务器将向双方发送对方的IP与端口,两个客户端可实现UDP连接。UDP具有打洞功能(即客户端1和2可以在两个不同的局域网中进行通信),但是前提是,服务器端必须使用的是公网IP。该程序服务端与客户端均在一个电脑上运行,如果想分开在多个电脑上运行,修改里面的IP地址即可。运行时必须先启动服务器。界面中,最上面的文本框为输入行,输入内容,一按回车,信息即发送。

具体流程:
启动服务器——监听端口——等待客户端的连接——启动客户端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");
}

}
}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值