Java实现两台电脑的通信(UDP)

【mie haha的博客】转载请注明出处(万分感谢!):
https://blog.csdn.net/qq_40315080/article/details/88830295

实现通信包含发送方和接收方两部分,但这两部分除了端口设置,其他代码完全相同,非常简单。

因为不同于之前写的聊天室篇使用TCP/IP进行通信,UDP通信不需要用Scocket建立起通信管道,直接发送包即可(不管对方能否收到),所以代码是对称的,只是起的名字不同而已。

以发送方为例:
1.它需要不停地发送消息和接收消息(发送方类似服务器,不只发送信息,也需要接收消息),需要用一个while(true)循环实现。
2.同时,发送方不只给一个接收方发送消息,可以给多个接收端发消息就像有好多个发送方在同时工作一样,这就需要把接收发送消息的功能写在线程中。
3.为了能更方便,还要给发送方写一个界面。
4.这样就可以在界面上点击发送按钮进行消息发送了,还需要一个监听器。
即:
发送方=监听器类(响应操作)+界面类(方便操作)+线程类(实现功能)
注:我把发送消息写在监听器类中,接收消息写在了线程类中

代码:
发送方:
【监听器类】

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import javax.swing.JTextField;
import javax.swing.plaf.synth.SynthSpinnerUI;

//监听器类,继承ActionListener
public class ButtonListener implements ActionListener {
	
	//输入框
	private JTextField jt;
	
    //创建要用来发送的本地地址
	SocketAddress localAddr = new InetSocketAddress("192.168.28.43", 6666);		
	
    private DatagramSocket dSender;
    
    //目标发送地址
    SocketAddress destAdd = new InetSocketAddress("192.168.28.43",9998);
    
	public ButtonListener(JTextField jt) {
		this.jt = jt;
	}

	//重写捕捉点击Action e鼠标点击时的响应操作
	public void actionPerformed(ActionEvent e) {

		try {
			
        if(dSender==null)				  
			// 2.创建发送的Socket对象
			 dSender = new DatagramSocket(localAddr);		
			int count = 0;
			while (count<1) {
				count++;
				byte buffer[] = (jt.getText()).getBytes();// 3.要发送的数据
				// 4.发送数据的目标地址和端口
				
				// 5.创建要发送的数据包,指定内容,指定目标地址
				DatagramPacket dp = new DatagramPacket(buffer, buffer.length, destAdd);
				dSender.send(dp);//发送
				System.out.println("数据已发送: " + jt.getText());
				
				jt.setText("");
				
				Thread.sleep(100);
			}

		} catch (Exception el) {

		}

	}
	
}

【界面类】


import java.awt.Dimension;

import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ReceiveFrame {
	public static void main(String[] args){
 	   ReceiveFrame rf = new ReceiveFrame();
 	   rf.initUI();
    } 
    
    public void initUI(){
 	   JFrame frame = new JFrame("接收方");
 	   frame.setSize(400,600);
 	   frame.setDefaultCloseOperation(3);
 	   frame.setLocationRelativeTo(null);
	       frame.setResizable(false);
		
		   FlowLayout flow = new FlowLayout();
		   frame.setLayout(flow);
		   JTextArea ja = new JTextArea();
		   Dimension dms = new Dimension(300,200);
		   ja.setPreferredSize(dms);
		   frame.add(ja);
		   JTextField jt = new JTextField();
		   Dimension dm = new Dimension(300,30);
		   jt.setPreferredSize(dm);
 	       frame.add(jt);
 	       JButton jb = new JButton("发送");
		   frame.add(jb);
 	       frame.setVisible(true);
 	   
 	   ButtonListener but = new ButtonListener(jt);
 	   jb.addActionListener(but);
 	 
 	   ReceiveThread rt = new ReceiveThread(ja);
 	   rt.start();
    }
}

【线程类】


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

import javax.swing.JTextArea;

//线程
public class ReceiveThread extends Thread{
	
	//信息显示部分
	private JTextArea ja;
	//接收地址
	SocketAddress localAddr = new InetSocketAddress("192.168.28.43", 9999);
	//数据包
	DatagramSocket recvSocket;

	//把界面上的信息显示部分传过来,构造函数
	public ReceiveThread(JTextArea ja){
  	 this.ja=ja;
   }
	
	//重写run方法
	public void run() {
		try {
			
			if(recvSocket==null)

          recvSocket = new DatagramSocket(localAddr);
			
			while(true){
				byte[] buffer = new byte[20]; // 3.指定接收缓冲区大小:每个包20字节
				// 4.创建接收数据包对象
				DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
				// 5.阻塞等待数据到来,如果收到数据,存入packet中的缓冲区中
				System.out.println("UDP服务器等待接收数据:");
				recvSocket.receive(packet); // 6.在此等待接收对方发的UDP包
				System.out.println("get");
				// 得到发送方的IP和端口
				SocketAddress address = packet.getSocketAddress();
				// 转换接收到的数据为字符串
				String msg = new String(packet.getData()).trim();
				msg+="\r\n";
				ja.append(msg);
				// 接收到后,打印出收到的数据长度
				System.out.println("recv is:" + msg + " from:" + address);
			}
		} catch (Exception el) {

		}
	}
}

接收方除了监听器类中的端口设置,其他与发送方完全相同。

接收端:
【监听器类】

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import javax.swing.JTextField;
import javax.swing.plaf.synth.SynthSpinnerUI;

public class ButtonListener implements ActionListener {
	
	//输入框
	private JTextField jt;
	
    //创建要用来发送的本地地址
	SocketAddress localAddr = new InetSocketAddress("192.168.28.43", 7777);		
	
    private DatagramSocket dSender;
    
    //目标发送地址
    SocketAddress destAdd = new InetSocketAddress("192.168.28.43",9999);
    
	public ButtonListener(JTextField jt) {
		this.jt = jt;
	}

	public void actionPerformed(ActionEvent e) {

		try {
			
        if(dSender==null)				  
			// 2.创建发送的Socket对象
			 dSender = new DatagramSocket(localAddr);		
			int count = 0;
			while (count<1) {
				count++;
				byte buffer[] = (jt.getText()).getBytes();// 3.要发送的数据
				// 4.发送数据的目标地址和端口
				
				// 5.创建要发送的数据包,指定内容,指定目标地址
				DatagramPacket dp = new DatagramPacket(buffer, buffer.length, destAdd);
				dSender.send(dp);// 6.发送
				System.out.println("数据已发送: " + jt.getText());
				
				jt.setText("");
				
				Thread.sleep(100);
			}

		} catch (Exception el) {

		}

	}
}

【界面类】


import java.awt.Dimension;

import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ReceiveFrame {
	public static void main(String[] args){
 	   ReceiveFrame rf = new ReceiveFrame();
 	   rf.initUI();
    } 
    
    public void initUI(){
 	   JFrame frame = new JFrame("接收方");
 	   frame.setSize(400,600);
 	   frame.setDefaultCloseOperation(3);
 	   frame.setLocationRelativeTo(null);
	       frame.setResizable(false);
		
		   FlowLayout flow = new FlowLayout();
		   frame.setLayout(flow);
		   JTextArea ja = new JTextArea();
		   Dimension dms = new Dimension(300,200);
		   ja.setPreferredSize(dms);
		   frame.add(ja);
		   JTextField jt = new JTextField();
		   Dimension dm = new Dimension(300,30);
		   jt.setPreferredSize(dm);
 	       frame.add(jt);
 	       JButton jb = new JButton("发送");
		   frame.add(jb);
 	       frame.setVisible(true);
 	   
 	   ButtonListener but = new ButtonListener(jt);
 	   jb.addActionListener(but);
 	 
 	   ReceiveThread rt = new ReceiveThread(ja);
 	   rt.start();
    }
}

【线程类】

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

import javax.swing.JTextArea;

//线程
public class ReceiveThread extends Thread{
	
	//信息显示部分
	private JTextArea ja;
	//接收地址
	SocketAddress localAddr = new InetSocketAddress("192.168.28.43", 9998);
	//数据包
	DatagramSocket recvSocket;
	
	
	//把界面上的信息显示部分传过来,构造函数
	public ReceiveThread(JTextArea ja){
  	 this.ja=ja;
   }
	
	//重写run方法
	public void run() {
		try {
			
			if(recvSocket==null)

          recvSocket = new DatagramSocket(localAddr);
			
			while(true){
				byte[] buffer = new byte[20]; // 3.指定接收缓冲区大小:每个包20字节
				// 4.创建接收数据包对象
				DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
				// 5.阻塞等待数据到来,如果收到数据,存入packet中的缓冲区中
				System.out.println("UDP服务器等待接收数据:");
				recvSocket.receive(packet); // 6.在此等待接收对方发的UDP包
				System.out.println("get");
				// 得到发送方的IP和端口
				SocketAddress address = packet.getSocketAddress();
				// 转换接收到的数据为字符串
				String msg = new String(packet.getData()).trim();
				msg+="\r\n";
				ja.append(msg);
				// 接收到后,打印出收到的数据长度
				System.out.println("recv is:" + msg + " from:" + address);
			}
		} catch (Exception el) {

		}
	}
}

这里注意一下,发送方和接收方的端口的设置
还是以发送方为例,要发送消息需要有一个自己发出消息的地址(本机地址+指定一个端口),目标发送端口(要发送到的地方的地址+端口),接收方将在这个地方进行监听接收。
(在监听器类中)。要接收消息时也有一个接收地址(在线程类中)。

两台电脑A和B分别作为发送端和接收端,怎样连接呢?
windows+r打开命令行,输入ipconfig查看自己的地址,查看无线局域网WLAN的IPv4地址,这样A和B都得到了自己的地址a,b。
A和B分别随便指定一个端口发出消息from_a,from_b,再约定要发送到的目标端口aim_a,aim_b。

匹配如图:在这里插入图片描述
以上代码中的监听器类和线程类中的地址(和端口)可按以上方法修改,这样就可以在两台电脑上进行互通了~

运行效果:
在这里插入图片描述
(如果把发送方和接收方的地址都改成自己的地址,就可以在自己的电脑上自己和自己连通了*~*)

界面还可以再继续美化。

以上代码全部完整。

如有错误,欢迎指出。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值