程序说明:

以下代码,利用java的网络编程,使用UDP通信作为通信协议,描述了一个简易的多人聊天程序,此程序可以使用公网或者是局域网进行聊天,要求有一台服务器。程序一共分为2个包,第一个包:udp,放置服务器端代码,包括:Server.java,第二个包:ui,放置客户端代码,包括:Login.java,Chat.java,Sender.java,Reciever.java,Test.java,期中Chat与Login为ui界面。

没有公网服务器的同学可以选择阿里云租赁【可以选择云翼计划】【非广告】,或者使用局域网,此代码使用公网ip测试成功,没有试过局域网,感兴趣的同学可以试一试。

具体代码:

Server.java:

 package udp;

 import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.util.LinkedList;
import java.util.List; public class Server
{ public static void main(String[] args)
{
new Thread(new Server_Run()).start();
} } class Server_Run implements Runnable
{
DatagramSocket server;
DatagramPacket packetIn = null;
DatagramPacket packetOut = null;
List<InetSocketAddress> addressList = new LinkedList<InetSocketAddress>(); public void doForThis() throws IOException
{
try
{
InetAddress local = InetAddress.getLocalHost();// 得到本地地址
System.out.println("Server local address:" + local);
server = new DatagramSocket(8823, local);// 8823负责接收 while (true)
{
byte[] buff = new byte[4096];
packetIn = new DatagramPacket(buff, 1024);
// 一旦调用这一方法, 会程序的阻塞, 直到你收到有数据报为止。
server.receive(packetIn); // 每次建立连接,获取用户地址,并存储在列表中
InetSocketAddress clientAddress = (InetSocketAddress) packetIn.getSocketAddress(); // 获取客户端地址
String ip = clientAddress.getAddress().getHostAddress();
int clientport = clientAddress.getPort();// 必须要通过端口号来找到客户端
if (!addressList.contains(clientAddress))
{
addressList.add(new InetSocketAddress(ip, clientport));
} byte[] temp = packetIn.getData();
int size = packetIn.getLength();
String content = new String(temp, 0, size, "UTF-8");
URLDecoder.decode(content, "utf-8");
if (size > 0)
{
System.out.println(content);
}
URLEncoder.encode(content, "utf-8");
for (InetSocketAddress clientisa : addressList)
{
packetOut = new DatagramPacket(content.getBytes("UTF-8"), 0, content.getBytes("UTF-8").length,
clientisa);// offset=0 偏移量
server.send(packetOut);
} }
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
} public void run()
{
try
{
doForThis();
} catch (IOException e)
{
e.printStackTrace();
}
} }

Login.java:

 package ui;

 import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern; import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager; class Login implements ActionListener, KeyListener
{ JFrame frame;
JLabel logo;
JLabel lbl1, lbl2;
JTextField jtf1, jtf2;
JButton jb1, jb2;
JPanel jp1, jp2, jp3, jp4;
ImageIcon img, head;
int width = 400;
int height = 650; String address;
String name;
public static void setUIFont()
{
Font f = new Font("宋体",Font.BOLD,18);
String names[]={ "Label", "CheckBox", "PopupMenu","MenuItem", "CheckBoxMenuItem",
"JRadioButtonMenuItem","ComboBox", "Button", "Tree", "ScrollPane",
"TabbedPane", "EditorPane", "TitledBorder", "Menu", "TextArea",
"OptionPane", "MenuBar", "ToolBar", "ToggleButton", "ToolTip",
"ProgressBar", "TableHeader", "Panel", "List", "ColorChooser",
"PasswordField","TextField", "Table", "Label", "Viewport",
"RadioButtonMenuItem","RadioButton", "DesktopPane", "InternalFrame"
};
for (String item : names) {
UIManager.put(item+ ".font",f);
}
} public Login() throws IOException
{
setUIFont();
img = new ImageIcon(Login.class.getResource("/img/logo.jpg"));
head = new ImageIcon(Login.class.getResource("/img/head.png"));// 此句暂时无效
img.setImage(img.getImage().getScaledInstance(width, 360, Image.SCALE_DEFAULT));
lbl1 = new JLabel("请输入服务器地址:");
lbl2 = new JLabel("请输入用户名:");
logo = new JLabel(img);// 预备图片
jb1 = new JButton("加入");
jb2 = new JButton("退出");
jb1.addActionListener(this);
jb2.addActionListener(this);
jtf1 = new JTextField(20);
jtf2 = new JTextField(20);
jp1 = new JPanel();
jp2 = new JPanel();
jp3 = new JPanel();
jp4 = new JPanel();
jp1.add(logo);
jp2.add(lbl1);
jp2.add(jtf1);
jp3.add(lbl2);
jp3.add(jtf2);
jp4.add(jb1);
jp4.add(jb2); jtf1.addKeyListener(this);// 绑定enter
jtf2.addKeyListener(this);// 绑定enter
frame = new JFrame("PLMM聊天室");
frame.setIconImage(head.getImage());
frame.setLayout(new FlowLayout(1, 20, 30));
frame.add(jp1);
frame.add(jp2);
frame.add(jp3);
frame.add(jp4);
frame.setLocationRelativeTo(null);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} // 以下代码判断ip是否可连接,未完成
// public boolean isHostConnectable(String host, int port)
// {
// Socket socket = new Socket();
// try
// {
// socket.connect(new InetSocketAddress(host, port));
// } catch (ConnectException e)
// {
// e.printStackTrace();
// return false;
// } catch (IOException e)
// {
// e.printStackTrace();
// return false;
// } finally
// {
// try
// {
// socket.close();
// } catch (IOException e)
// {
// e.printStackTrace();
// }
// }
// return true;
// } // // 以下代码判断ip是否超时
public boolean isHostReachable(String host, Integer timeOut)
{
try
{
return InetAddress.getByName(host).isReachable(timeOut);
} catch (ConnectException e)
{
e.printStackTrace();
} catch (UnknownHostException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return false;
} public void connect()
{
// 下面判断用户名
if (jtf2.getText().length() > 8)
{ // 对用户名长度进行限制
JOptionPane.showMessageDialog(null, "用户名长度必须小于8!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (jtf2.getText().length() == 0)
{ // 为空判断
JOptionPane.showMessageDialog(null, "用户名不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} else
{
name = jtf2.getText();
}
// 下面判断ip地址
address = jtf1.getText();
Pattern pattern = Pattern.compile(
"^(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])$"); // IP正则表达式
boolean flag = pattern.matcher(address).matches();
if (address.length() == 0)
{ // 为空判断
JOptionPane.showMessageDialog(null, "IP地址不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (flag == false)
{ // IP正则匹配
JOptionPane.showMessageDialog(null, "IP地址不正确!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (isHostReachable(address, 1000) == false)
{// 判断是否连接超时
JOptionPane.showMessageDialog(null, "IP连接超时!", "Warning", JOptionPane.ERROR_MESSAGE);
} else
{
frame.setVisible(false); // 如何实现真正的关闭?且不退出程序(不中断下一步执行)
frame = null;
frame = new Chat(address, name);// 传入address
}
} public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jb1)
{
connect(); } else if (e.getSource() == jb2)
{
System.exit(0);
}
} public void keyTyped(KeyEvent e)
{ } public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
connect();
} } public void keyReleased(KeyEvent e)
{ } }

Chat.java:

 package ui;

 import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea; public class Chat extends JFrame implements ActionListener, KeyListener
{
private static final long serialVersionUID = 1L;
double initWidth = 800;
double initHeight = 600; JPanel jp1, jp2; // 定义面板
JSplitPane jsp; // 定义拆分窗格
JTextArea jta1, jta2; // 定义文本域
JScrollPane jspane1, jspane2; // 定义滚动窗格 JButton jb1, jb2; // 定义按钮 String addressSTR;
String name;
String messageOut = "";
String messageIn = ""; public Chat(String addressSTR, String name)
{ this.addressSTR = addressSTR;
this.name = name; jta1 = new JTextArea(); // 创建多行文本框
jta2 = new JTextArea();
jta1.setLineWrap(true); // 设置多行文本框自动换行
jta1.setEditable(false); // 禁止用户修改公屏信息
jta1.addKeyListener(this);
jta2.setLineWrap(true);
jta2.addKeyListener(this);
jspane1 = new JScrollPane(jta1); // 创建滚动窗格
jspane2 = new JScrollPane(jta2);
jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, jspane1, jspane2); // 创建拆分窗格 double initSep = initHeight * 2 / 3; jsp.setDividerLocation((int) initSep); // 设置拆分窗格分频器初始位置
jsp.setDividerSize(1); // 设置分频器大小
jb1 = new JButton("发送"); // 创建按钮
jb2 = new JButton("关闭");
jb1.addActionListener(this);
jb2.addActionListener(this);
jp1 = new JPanel(); // 创建面板
jp2 = new JPanel();
jp1.setLayout(new BorderLayout()); // 设置面板布局
jp2.setLayout(new FlowLayout(FlowLayout.RIGHT));
jp1.add(jsp); // 分频器
jp2.add(jb1); // 按钮
jp2.add(jb2); this.add(jp1, BorderLayout.CENTER);
this.add(jp2, BorderLayout.SOUTH); // 设置窗体实行
this.setTitle("澳门聊天室-人间天堂"); // 设置界面标题
// this.setIconImage(new ImageIcon(User_chat.class.getClassLoader().getResource("Head.png")).getImage());
this.setSize((int) initWidth, (int) initHeight); // 设置界面像素
this.setLocationRelativeTo(null); // 居中运行
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置虚拟机和界面一同关闭
this.setVisible(true); // 设置界面可视化 new Thread(new Reciever(addressSTR, messageIn, jta1)).start();
} public void sendOut()
{
messageOut = jta2.getText();
if (messageOut.hashCode() != 0) // 此处必须用hash
{
new Thread(new Sender(addressSTR, name, messageOut)).start();
jta2.setText("");
} else
{
JOptionPane.showMessageDialog(null, "发送消息不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} } public void scrollAndSetCursor(JTextArea jta)
{
// 自动滚动
jta.setSelectionStart(jta.getText().length()); } public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jb1)
{
// 发送
sendOut(); } else if (e.getSource() == jb2)
{
System.exit(0); }
} public void keyTyped(KeyEvent e)
{ } public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_CONTROL + KeyEvent.VK_ENTER)
{
sendOut();
}
} public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
jta2.setText("");
} }
}

Sender.java:

 package ui;

 import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.URLEncoder;
import java.net.UnknownHostException; public class Sender implements Runnable
{
String address = "";
String name = "";
DatagramSocket socket = null;
DatagramPacket packetOut = null;
String messageOut = ""; public Sender(String address, String name, String messageOut)
{
this.address = address;
this.name = name;
this.messageOut = messageOut;
} public void doForThis() throws IOException
{ try
{
if (messageOut.length() != 0)
{
socket = new DatagramSocket(8823); // 进行一次发送
InetSocketAddress isa = new InetSocketAddress(address, 8823); String content = name + ":" + messageOut;
URLEncoder.encode(content, "utf-8"); packetOut = new DatagramPacket(content.getBytes("UTF-8"), content.getBytes("UTF-8").length, isa);
socket.send(packetOut);
messageOut = "";
socket.close();
// socket.receive(packetOut);
// String message = new String(packetOut.getData(), 0, packetOut.getLength());
// System.out.println("本机端口和IP信息:" + message);
// int clientListenPort = Integer.valueOf(message.split(":")[1]);
// System.out.println(clientListenPort);
}
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnknownHostException e)
{
e.printStackTrace();
} finally
{ } } public void run()
{
try
{
System.out.println("sender is running");
doForThis();
} catch (IOException e)
{
e.printStackTrace(); }
} }

Reciever.java:

 package ui;

 import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.URLDecoder; import javax.swing.JTextArea; public class Reciever implements Runnable
{
String strAddress = "";
String name = "";
String messageOut = "";
String messageIn = "";
DatagramSocket socket = null;
DatagramPacket packet = null;
int clientListenPort;
JTextArea jta1; public Reciever(String strAddress, String messageIn, JTextArea jta1)
{
this.strAddress = strAddress;
this.messageIn = messageIn;
this.jta1 = jta1;
} // @SuppressWarnings("resource") 此处也不能加
public void doForThis() throws IOException
{
SocketAddress server = new InetSocketAddress(strAddress, 8823);
@SuppressWarnings("resource")
DatagramSocket ds = new DatagramSocket(); // ds必须经过一次发送和接收,为什么呢?
byte buff[] = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff, 0, 0, server);
ds.send(dp);// 发送信息到服务器
ds.receive(dp);
try
{
socket = new DatagramSocket(); // 负责接收 while (true)
{
packet = new DatagramPacket(buff, 1024);// 实现接收 ds.receive(packet); byte[] temp = packet.getData();
int size = packet.getLength();
if (size > 0)
{
String content = new String(temp, 0, size, "UTF-8");
// System.out.println(content);
URLDecoder.decode(content, "utf-8");
messageIn = "\n" + content;
jta1.append(messageIn);
// 自动滚动
scrollAndSetCursor(jta1);
}
}
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
} public void scrollAndSetCursor(JTextArea jta)
{
// 自动滚动
jta.setSelectionStart(jta.getText().length()); } public void run()
{
try
{
System.out.println("receiver is running");
doForThis();
} catch (IOException e)
{
e.printStackTrace();
}
}
}

Test.java:

 package ui;

 import java.io.IOException;

 public class Test
{
public static void main(String[] args) throws IOException
{
new Login();
}
}

测试结果:

注意我Login代码里的img,没有在对应路径放置图片的话是无法显示的,我放在bin目录下自己创建的img文件夹里。

登录界面,【忽略窗口名】:

登录进去后,测试聊天【忽略窗口名】:

转载请说明原文地址,谢谢!

Java入门网络编程-使用UDP通信的更多相关文章

  1. java:网络编程(UDP (DatagramSocket和DatagramPacket)正则表达式)

    java:网络编程(UDP (DatagramSocket和DatagramPacket)正则表达式) * TCP* 特点:面向连接,点对点的通信,效率较低,但安全可靠* UDP:用户数据报协议,类似 ...

  2. 网络编程 单纯UDP通信

    网络编程 单纯UDP通信 1,UDP发送端 2,UDP接收端 UDP发送端: #include <stdio.h> #include <unistd.h> #include & ...

  3. [javaSE] 网络编程(UDP通信)

    UDP发送端 获取DatagramSocket对象,new出来 获取DatagramPacket对象,new出来,构造参数:byte[]数组,int长度,InetAddress对象,int端口 调用D ...

  4. java基础-网络编程(Socket)技术选型入门之NIO技术

    java基础-网络编程(Socket)技术选型入门之NIO技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传统的网络编程 1>.编写socket通信的MyServer ...

  5. JAVA的网络编程

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

  6. 【转】JAVA之网络编程

    转自:火之光 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者 ...

  7. JAVA的网络编程【转】

    JAVA的网络编程[转] Posted on 2009-12-03 18:04 火之光 阅读(93441) 评论(20) 编辑 收藏 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能, ...

  8. 二十三、Java基础--------网络编程

    Java中另一个重要技术就是网络编程了,为了更好的学习web方向的知识,有必要对java之网络编程好好学习,本文将围绕网络编程技术进行分析. 常见的网络协议:UDP.TCP UDP 1. 将数据源和目 ...

  9. Java面向对象 网络编程 上

     Java面向对象 网络编程 上 知识概要:                     (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...

随机推荐

  1. yii2.0获取最后一条ID

    $r_id=Yii::$app->db->getLastInsertID();

  2. 统计推断(statistical inference)

    样本是统计推断的依据: 统计推断的基本问题可以分为两大类: 估计问题 点估计, 区间估计 假设检验 1. 点估计 设总体 X 的分布函数 F(x;θ) 的形式已知,θ 是待估参数.X1,X2,-,Xn ...

  3. 浏览器兼容性之ECMAScript

    1 IE中不能操作TR标签的innnerHTML. 2 日期处理函数不一致. (1)IE 8- new Date().getYear()返回的是到当前日期到1900年的差值,FF返回的是当前的年. ( ...

  4. 【每日一句】make a scene

    scene有场面.场景的意思,只是make a scene可不是指做场面.scene还有还有一个意思,指很生气而大吵大闹(的情景),因此make a scene就是指某人情绪失控发脾气.如今一起从以下 ...

  5. day68_淘淘商城项目_01

    原文:day68_淘淘商城项目_01 课程计划 第一天: 1.电商行业的背景介绍--电子商务 2.淘淘商城的系统架构 a) 功能介绍 b) 架构讲解 3.工程搭建--后台工程 a) 使用maven搭建 ...

  6. C++安全异常std:auto_ptr

    auto_ptr它是C++标准库(<utility>)为了一个智能指针类模板来解决资源泄漏所提供的问题(注意:这只是一个简单的智能指针) auto_ptr在事实原则的实现RAII,对资源的 ...

  7. VC实现程序重启的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 很多时候系统有很多配置项,修改了配置项之后能有一个按钮实现系统重启.所谓重启就是杀死系统的当前进程,然后重新开一个新进 ...

  8. ListView、TreeView和DataGrid。

    原文:ListView.TreeView和DataGrid. 1.ListView. ListView继承自简单的没有特色的ListBox,并使用View属性进行扩展.增加了对基于列显示的支持,并增加 ...

  9. jquery权限选择

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  10. C#异步委托等待句柄的使用

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...