程序说明:

以下代码,利用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. wpf中xaml的类型转换器与标记扩展

    原文:wpf中xaml的类型转换器与标记扩展 这篇来讲wpf控件属性的类型转换器 类型转换器 类型转换器在asp.net控件中已经有使用过了,由于wpf的界面是可以由xaml组成的,所以标签的便利也需 ...

  2. Win7 32bit下一个hadoop2.5.1源代码编译平台的搭建各种错误遇到

    从小白在安装hadoop困难和错误时遇到说起,同时,我们也希望能得到上帝的指示. 首先hadoop更新速度非常快,最新的是hadoop2.5.1,因此就介绍下在安装2.5.1时遇到的各种困难. 假设直 ...

  3. Customize Acrylic Brush in UWP Applications(在UWP中自定义亚克力笔刷)

    原文 Customize Acrylic Brush in UWP Applications(在UWP中自定义亚克力笔刷) Windows 10 Fall Creators Update(Build ...

  4. Windows搭建Eclipse+JDK+SDK的Android --安卓开发入门级

     一 相关下载 (1) java JDK下载: 进入该网页: http://java.sun.com/javase/downloads/index.jsp (或者直接点击下载)例如以下图: 选择 ...

  5. Qt 绘制平滑曲线

    本文介绍在 Qt 中绘制平滑曲线的实现,调用下面的函数 SmoothCurveGenerator::generateSmoothCurve(points) 即可.默认曲线的 2 个顶点之间被分割为 1 ...

  6. NYOJ 298 相变点(矩阵高速功率)

    点的变换 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描写叙述 平面上有不超过10000个点.坐标都是已知的.如今可能对全部的点做下面几种操作: 平移一定距离(M),相对X ...

  7. js onload事件使用

    <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  8. jquery 克隆div 复制div 克隆元素 复制元素

    代码: $('.div1').clone() 定义和用法 clone() 方法生成被选元素的副本,包含子节点.文本和属性. 语法 $(selector).clone(includeEvents) 参数 ...

  9. [原译]一步步教你制作WPF圆形玻璃按钮

    原文:[原译]一步步教你制作WPF圆形玻璃按钮 图1 1.介绍 从我开始使用vista的时候,我就非常喜欢它的圆形玻璃按钮.WPF最好的一个方面就是允许自定义任何控件的样式.用了一段时间的Micros ...

  10. 创建hexo风格的markdown页面

    最近在用 nodejs 搭建一个个人博客,博客当然要有编辑文章的功能啦.个人比较偏爱 hexo 风格的 markdown 格式,所以想自己的博客也是这样的风格.尝试了几个库,发现 marked 的转换 ...