Java网络编程之UDP实现原理解析


Posted in Java/Android onSeptember 04, 2021

UDP实现通信非常简单,没有服务器,每个都是客户端,每个客户端都需要一个发送端口和一个接收端口。一个客户端向另一个客户端发送消息时,需要知道对方的IP和接收端口,所用到的类为DatagramSocket。

DatagramSocket socket =new DatagramSocket(),发送端socket,若不指定端口,系统自动分配

DatagramSocket socket =new DatagramSocket("接收信息端口"),接收端socket,需要指定接收端口

​ 若想客户端之间进行全双工通信,每个客户端都要有两个线程,一个用于发送信息,一个用于接收信息。

​ 那么UDP怎么实现私聊和群聊呢?(在本机一台电脑的情况下实现)

​ 首先私聊,客户端向另一个客户端发送消息,就要知道其IP(本机都是固定的localhost)和接收端口,也需要姓名进行标识,所以,每个客户端都至少要自己的姓名和接收端口,而且端口不可重复,否则会报端口被占用的错。

​ 其次群聊,由于在本机一台电脑上进行,接收端口各不相同,所以广播就不行了,此时就希望每个客户端在启动的时候,能够把自己的姓名和接收端口给存起来,然后就可以遍历进行群聊。

​ 实现:

  • 第一种,在每个客户端启动时,输入自己的姓名和接收端口,发送信息时,需要输入对方的接收端口号,如果输入时输入了多个端口,就是群发。那么这样每次发送信息时都要指定对方的端口。。。
  • 第二种,客户端启动时,输入姓名和接收端口,此时就把数据存起来,发送信息时,只用指定对方姓名即可。。。可用数据库存,可用文件存,我用的是XML来存。

要创建xml文件,路径在Operation类中

UdpClient.java:

public class UdpClient {

	public static void main(String[] args) {
		try {
			Scanner scanner = new Scanner(System.in);
			User user = new User();
			System.out.print("请输入用户名》》");
			String userName = scanner.next();
			if (Operation.userIsExist(userName)) {
				//如果此用户已经注册过,直接把注册时用的接收端口分配给他
				user = Operation.findUserByName(userName);
			}else {
				//未注册,用户自己指定端口
				while(true) {
					System.out.println("请输入接收端口》》");
					int port = Integer.parseInt(scanner.next());
					if (Operation.portIsExist(port)) {
						System.err.println("该端口已被使用,请重新输入。。。。");
						continue;
					}else {
						user.setName(userName);
						user.setPort(port);
						Operation.addUser(user);
						break;
					}
				}
			}
			new Thread(new SendMsg(user)).start();
			new Thread(new ReceiveMsg(user)).start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

发送信息:

public class SendMsg implements Runnable{

	private User self = null;
	private DatagramSocket socket = null;
	private BufferedReader reader = null;
	public SendMsg(User self) {
		try {
			socket = new DatagramSocket();
			reader = new BufferedReader(new InputStreamReader(System.in));
			this.self = self;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Override
	public void run() {	
		try {
			while(true) {
				String[] msg = reader.readLine().split("@");
				if (msg.length != 2) {
					System.err.println("注意格式:消息@对方名字(私聊)或all(群聊)");
					continue;
				}
				msg[0] = self.getName()+"说:"+msg[0];
				byte[] data = msg[0].getBytes();
				String toPerson = msg[1];
				if (("all").equals(toPerson)) {
					//群聊,获取所有用户,不管对方在不在线,都发过去
					List<User> users = Operation.getUsers();
					for(User user:users) {
						if (self != user) {
							DatagramPacket packet = new DatagramPacket(data, 0,data.length,new InetSocketAddress("localhost",user.getPort()));
						    socket.send(packet);
						}
					}
				}else {
					//私聊
					try {
						DatagramPacket packet = new DatagramPacket(data, 0,data.length,new InetSocketAddress("localhost",Operation.findUserByName(toPerson).getPort()));
				        socket.send(packet);
					} catch (Exception e) {
						System.out.println("对方不在线。。。");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

接收消息:

public class ReceiveMsg implements Runnable{

	private DatagramSocket socket = null;
	public ReceiveMsg(User user) {
		try {
			socket = new DatagramSocket(user.getPort());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		try {
			while(true) {
				//准备接收包裹
				byte[] container = new byte[1024];
				DatagramPacket packet = new DatagramPacket(container,0,container.length);
				socket.receive(packet);
				byte[]data = packet.getData();
				String receiveData = new String(data, 0, data.length);
				System.out.println(receiveData);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		socket.close();
	}
}

操作XML文件类:

public class Operation {
	private static String FILE_PATH = "config/user.xml";     //文件目录
 
        //在xml文件中添加一个用户信息
	public static void addUser(User user)
	{
		InputStream in = null;
		SAXReader reader = new SAXReader();
		Document doc = null;
		try
		{
			in = new FileInputStream(FILE_PATH);
			doc = reader.read(in);
			Element root = doc.getRootElement();   //获取xml根节点,即users节点
			Element element = root.addElement("user");
			element.addElement("name").addText(user.getName());
			element.addElement("port").addText(String.valueOf(user.getPort()));
 
			FileOutputStream fos = new FileOutputStream(FILE_PATH);
			//格式化xml文件
			OutputFormat format = OutputFormat.createPrettyPrint();
			format.setEncoding("utf-8");
			XMLWriter writer = new XMLWriter(fos,format);
			writer.write(doc);
			writer.close();
		}
		catch (Exception e)
		{
			System.out.println("error");
		}
		finally
		{
			try
			{
			
				if(in != null)
					in.close();
			}
			catch (IOException e)
			{
				System.out.println("error");
			}
		}
	}
 
        //列出xml中所有用户信息
	public static List<User> getUsers()
	{
		InputStream in = null;
		SAXReader reader = new SAXReader();
		Document doc = null;
		List<User> users = new ArrayList<>();
		try
		{
			in = new FileInputStream(FILE_PATH);
			doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> elements = root.elements();
			for (Element element : elements)
			{
				User user = new User();
				user.setName(element.elementText("name"));
				user.setPort(Integer.valueOf(element.elementText("port")));
				users.add(user);
			}
		}
		catch (Exception e1)
		{
			System.out.println("error");
		}
		finally
		{
			try
			{
				in.close();
			}
			catch (IOException e)
			{
				System.out.println("error");
			}
		}
 
		return users;
	}
	public static User findUserByName(String name) {
		InputStream in = null;
		SAXReader reader = new SAXReader();
		Document doc = null;
		try {
			in = new FileInputStream(FILE_PATH);
			doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> elements = root.elements();
			for (Element element : elements)
			{
				if(name != null && name.equals(element.elementText("name"))) {
					User user = new User();
					user.setName(name);
					user.setPort(Integer.parseInt(element.elementText("port")));
					return user;
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static boolean portIsExist(int port) {
		InputStream in = null;
		SAXReader reader = new SAXReader();
		Document doc = null;
		
		try {
			in = new FileInputStream(FILE_PATH);
			doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> elements = root.elements();
			for (Element element : elements)
			{
				if(port == Integer.parseInt(element.elementText("port")))
					return true;
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return false;
	}
        //判断某个用户是否存在该xml中
	public static boolean userIsExist(String name) 
	{
		InputStream in = null;
		SAXReader reader = new SAXReader();
		Document doc = null;
		try {
			in = new FileInputStream(FILE_PATH);
			doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> elements = root.elements();
			for (Element element : elements)
			{
				if(name != null && name.equals(element.elementText("name")))
					return true;
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return false;
	}
}

用户实体类:

public class User implements Serializable{

	private String name;//姓名
	private int port;//接收端口
	public String getName() {
		return name;
	}
	public int getPort() {
		return port;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setPort(int port) {
		this.port = port;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", port=" + port + "]";
	}
	
}

运行结果:
Java网络编程之UDP实现原理解析

Java网络编程之UDP实现原理解析

到此这篇关于Java网络编程之UDP实现原理解析的文章就介绍到这了,更多相关Java网络编程UDP内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
Java输出Hello World完美过程解析
Jun 13 Java/Android
自从在 IDEA 中用了热部署神器 JRebel 之后,开发效率提升了 10(真棒)
Jun 26 Java/Android
SpringBoot整合JWT的入门指南
Jun 29 Java/Android
新手初学Java网络编程
Jul 07 Java/Android
java解析XML详解
Jul 09 Java/Android
JavaWeb 入门篇:创建Web项目,Idea配置tomcat
Jul 16 Java/Android
详解Java七大阻塞队列之SynchronousQueue
Sep 04 Java/Android
SpringBoot中获取profile的方法详解
Apr 08 Java/Android
Java数组详细介绍及相关工具类
Apr 14 Java/Android
Java工作中实用的代码优化技巧分享
Apr 21 Java/Android
Java由浅入深通关抽象类与接口(上篇)
Apr 26 Java/Android
Android实现获取短信验证码并自动填充
May 21 Java/Android
Java spring单点登录系统
详解Java七大阻塞队列之SynchronousQueue
java中用float时,数字后面加f,这样是为什么你知道吗
Sep 04 #Java/Android
SpringBoot实现quartz定时任务可视化管理功能
Aug 30 #Java/Android
logback 实现给变量指定默认值
Aug 30 #Java/Android
SpringMVC 整合SSM框架详解
Aug 30 #Java/Android
使用logback实现按自己的需求打印日志到自定义的文件里
Aug 30 #Java/Android
You might like
php中http_build_query 的一个问题
2012/03/25 PHP
PHP实现链式操作的核心思想
2015/06/23 PHP
PHP微信网页授权的配置文件操作分析
2019/05/29 PHP
JavaScript中的类数组对象介绍
2014/12/30 Javascript
JavaScript获得页面base标签中url的方法
2015/04/03 Javascript
jquery实现动态改变div宽度和高度
2015/05/08 Javascript
浅析jQuery Ajax请求参数和返回数据的处理
2016/02/24 Javascript
基于BootStrap Metronic开发框架经验小结【四】Bootstrap图标的提取和利用
2016/05/12 Javascript
js 判断附件后缀的简单实现方法
2016/10/11 Javascript
js表单登陆验证示例
2016/10/19 Javascript
关于react-router的几种配置方式详解
2017/07/24 Javascript
AngularJS实现的根据数量与单价计算总价功能示例
2017/12/26 Javascript
vue实现点击关注后及时更新列表功能
2018/06/26 Javascript
深入浅析angular和vue还有jquery的区别
2018/08/13 jQuery
uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能
2019/11/12 Javascript
JavaScript获取当前url路径过程解析
2019/12/27 Javascript
vue实现简单的登录弹出框
2020/10/26 Javascript
[49:21]完美世界DOTA2联赛循环赛 Ink Ice vs LBZS BO2第二场 11.05
2020/11/06 DOTA
pycharm 使用心得(三)Hello world!
2014/06/05 Python
Python设计模式中单例模式的实现及在Tornado中的应用
2016/03/02 Python
python中WSGI是什么,Python应用WSGI详解
2017/11/24 Python
Python使用numpy实现BP神经网络
2018/03/10 Python
python装饰器常见使用方法分析
2019/06/26 Python
Python 多个图同时在不同窗口显示的实现方法
2019/07/07 Python
python3的print()函数的用法图文讲解
2019/07/16 Python
Python实现微信小程序支付功能
2019/07/25 Python
Python实现计算图像RGB均值方式
2020/06/04 Python
Python中Yield的基本用法
2020/10/18 Python
韩国休闲女装品牌网站:ANAIS
2016/08/24 全球购物
在网络中有两台主机A和B,并通过路由器和其他交换设备连接起来,已经确认物理连接正确无误,怎么来测试这两台机器是否连通?如果不通,怎么来判断故障点?怎么排
2014/01/13 面试题
酒店应聘自荐信
2013/11/09 职场文书
教师队伍管理制度
2014/01/14 职场文书
节电标语大全
2014/06/23 职场文书
幼儿园六一儿童节活动方案
2014/08/26 职场文书
镇人大副主席民主生活会对照检查材料思想汇报
2014/10/01 职场文书
有关朝花夕拾的读书笔记
2015/06/29 职场文书