您的位置 首页 java

Java网络编程之UDP

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

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

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

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

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

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

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

​ 实现:

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

文章地址:https://www.zhihuclub.com/182208.shtml

关于作者: 智云科技

热门文章

网站地图