文章目录
1. 简介
1.1 功能
一个服务端,两个客户端。客户端将消息发送到服务端,由服务端对消息进行转发。以实现两个客户端通过服务端进行点对点通信。
1.2 技术
- 语言:java
- DatagramPacket和DatagramSocket,实现模拟UDP协议(通过端口实现两个进程间的通信)
1.3 流程
客户端1(2)通过端口号找到服务端,将消息发送给服务端;服务端接收到消息后,将接收到的内容转发给客户段2(1)
2. 源码
2.1 客户端1
package Socket2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.*;
/*
模拟客户端 - 普通 Socket 实现
*/
public class Client1 {
public static void main ( String [] args ) throws IOException {
System.out.println("输入0,发送消息 输入1,接收消息 输入2,停止收发消息 ");
//创建DatagramSocket对象
DatagramSocket socket=new DatagramSocket(null);
socket.bind(new InetSocketAddress(9999));//绑定本地端口
System.out.println("正常1");
//定义服务器的地址、端口号、数据
InetAddress address=InetAddress.getByName("localhost");
int port=9000;
while(true)
{
Scanner input=new Scanner(System.in);
int choose=input.nextInt();
if(choose==0)
{
String inputdata=input.next();
byte[] data=inputdata.getBytes("UTF-8");//拒绝乱码TT-TT
//创建数据报
DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
//向服务器端发送数据报
socket.send(packet);
System.out.println("正常2");
}
else if(choose==1)
{
byte[] data2=new byte[1024];
DatagramPacket packet2=new DatagramPacket(data2, data2.length);
//接收服务器响应的数据
socket.receive(packet2);
//读取数据
String reply=new String(packet2.getData(),"UTF-8");
System.out.println("接收消息:"+reply);
}
else if(choose==2)
{
//关闭资源
socket.close();
System.out.println("已结束");
}
else
{
System.out.println("请输入正确数字");
}
}
}
}
2.2 客户端2(与客户端1不同的只有端口号)
package Socket2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.*;
/*
模拟客户端 - 普通 Socket 实现
*/
public class Client2 {
public static void main ( String [] args ) throws IOException {
System.out.println("输入0,发送消息 输入1,接收消息 输入2,停止收发消息 ");
//创建DatagramSocket对象
DatagramSocket socket=new DatagramSocket(null);
socket.bind(new InetSocketAddress(9998));//绑定本地端口
//定义服务器的地址、端口号、数据
InetAddress address=InetAddress.getByName("localhost");
int port=9000;
while(true)
{
Scanner input=new Scanner(System.in);
int choose=input.nextInt();
if(choose==0)
{
String inputdata=input.next();
byte[] data=inputdata.getBytes("UTF-8");//拒绝乱码TT-TT
//创建数据报
DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
//向服务器端发送数据报
socket.send(packet);
}
else if(choose==1)
{
byte[] data2=new byte[1024];
DatagramPacket packet2=new DatagramPacket(data2, data2.length);
//接收服务器响应的数据
socket.receive(packet2);
//读取数据
String reply=new String(packet2.getData(),"UTF-8");
System.out.println("接收消息:"+reply);
}
else if(choose==2)
{
//关闭资源
socket.close();
System.out.println("已结束");
}
else
{
System.out.println("请输入正确数字");
}
}
}
}
2.3 服务端
package Socket2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
服务器端
端口号9000
*/
public class Server
{
public static void main(String[] args) throws IOException
{
DatagramSocket socket=new DatagramSocket(9000); //端口9000
System.out.println("服务器端已经启动,等待客户端发送数据");
byte[] data =new byte[1024];
DatagramPacket packet=new DatagramPacket(data, data.length); //指定接收包的大小为1024
int finish=0;
while(true)
{
//接收到数据报之前会一直阻塞
socket.receive(packet);
//读取数据
String info=new String(packet.getData(),"UTF-8");
System.out.println("-------------------------------------------");
System.out.println("成功接收数据 ");
System.out.println("源端口号:"+packet.getPort());
System.out.println("接收数据:"+info);
System.out.println("-------------------------------------------");
//向本机地址,指定端口的客户端发送数据
InetAddress address=packet.getAddress();
int port=packet.getPort();
String message=new String (packet.getData(),"UTF-8");
//指定发送端口
int sendport=port;
if(port==9999)
{
sendport=9998;
}
else
{
sendport=9999;
}
byte[] data2=message.getBytes("UTF-8");
DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, sendport);
socket.send(packet2);
System.out.println("-------------------------------------------");
System.out.println("成功发送数据 ");
System.out.println("目的端口号:"+sendport);
System.out.println("发送数据:"+message);
System.out.println("-------------------------------------------");
if(finish==1)
{
socket.close();
}
}
}
}
3. 运行
(我使用的是eclipse,需要开三个结果窗口,并且三个源码在同一个包中)
- 首先运行服务端,此时会显示已经打开服务端的提示信息,不需要进行任何操作,直接将结果窗口固定住。
- 运行客户端1,输入数字1,等待接收消息,将结果窗口固定住。
- 运行客户端2,输入数字0,选择发送消息功能。任意输入一条要发送的数据(比如“你好,我是客户端2”),按下enter键。固定住结果窗口
- 此时,服务端会接收到消息,并将数据转发给客户端1。在已经固定在服务端结果的结果界面中,可以观察到相关提示信息。
- 再看客户端1的结果窗口,已经接收到客户端2发送过来的信息。
此时已经成功完成了一次客户端2向客户端1发送消息。
4. 注意
4.1 端口占用
这三个程序都只能运行一次后持续开着,如果再次运行,会报错:端口被占用。这时需要打开资源管理器,将eclipse下的java进程结束,释放端口,才能再次运行。
4.2 运行时注意事项
按照顺序依次运行程序后,不需要再次点击运行。进程会一直保持开启并使用状态,结果可以通过开通三个结果窗口,每个窗口对应一个进程,可以观察到每个进程的持续性变化。