[java]基于UDP的Socket通信Demo
java课编程作业:在老师给的demo的基础上实现客户端发送数据到服务器端,服务器端接受客户端后进行数据广播。
整体功能类似于聊天室,代码部分不是太难,但是在本机测试的时候出现这样的问题:
服务端通过将每一个Socket客户端的IP存入Set集合,每次接受到数据后都向当前所有的IP转发。但是本机演示的时候所有开的ChatClient客户端都是同一IP,怎么测试呢?
解决办法就是本机测试时候服务端向多个不同的端口转发就好了,这样跑起来的客户端是在不同端口上进行监听的(只是为了实现广播,实际应用下还是通过IP来转发)。
客户端代码:
import javax.print.attribute.HashPrintServiceAttributeSet;
import javax.swing.*; import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*; public class ChatClient extends JFrame { JTextArea contents = new JTextArea();
JLabel label1 = new JLabel("服务器地址");
JTextField address = new JTextField();
JLabel label2 = new JLabel("用户名");
JTextField username = new JTextField();
JButton online = new JButton("上线");
JButton offline = new JButton("下线");
JTextField input = new JTextField();
JButton send = new JButton("发送"); boolean onlineFlag = false; public ChatClient() {
super("Chat Client"); contents.setEditable(false);
getContentPane().add(contents); JPanel p1 = new JPanel();
p1.setLayout(new FlowLayout(FlowLayout.LEADING)); address.setPreferredSize(new Dimension(100, 28));
username.setPreferredSize(new Dimension(80, 28));
input.setPreferredSize(new Dimension(180, 28)); p1.add(label1);
p1.add(address);
p1.add(label2);
p1.add(username);
p1.add(online);
p1.add(offline);
p1.add(input);
p1.add(send); offline.setEnabled(false);
send.setEnabled(false); getContentPane().add(p1, BorderLayout.SOUTH); addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
onlineFlag = false;
Map<String, Object> m1 = new HashMap<String, Object>();
m1.put("time", new Date()); // 上线时间
m1.put("username", getUsername());
m1.put("onlineFlag", onlineFlag); send(getServerAddress(), 2222, m1); System.exit(0);
}
}); ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String server = getServerAddress();
if (server == null || server.length() == 0) {
JOptionPane.showMessageDialog(ChatClient.this, "请输入服务器地址!");
return;
} if (ae.getSource() == online) {
// 用户点击了上线按钮
if (!onlineFlag) {
onlineFlag = true;
Map<String, Object> m1 = new HashMap<String, Object>();
m1.put("time", new Date()); // 上线时间
m1.put("username", getUsername());
m1.put("onlineFlag", onlineFlag);
online.setEnabled(false);
offline.setEnabled(true);
send.setEnabled(true);
address.setEnabled(false);
username.setEnabled(false);
send(getServerAddress(), 2222, m1); }
} else {
// 用户点击了下线按钮
if (onlineFlag) {
onlineFlag = false;
Map<String, Object> m1 = new HashMap<String, Object>();
m1.put("time", new Date()); // 上线时间
m1.put("username", getUsername());
m1.put("onlineFlag", onlineFlag);
online.setEnabled(true);
offline.setEnabled(false);
send.setEnabled(false);
address.setEnabled(true);
username.setEnabled(true);
send(getServerAddress(), 2222, m1);
}
}
}
}; ActionListener al2 = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Map<String, Object> m1 = new HashMap<String, Object>();
m1.put("time", new Date());
m1.put("username", getUsername());
m1.put("input", getInput());
send(getServerAddress(), 2222, m1);
}
}; send.addActionListener(al2); online.addActionListener(al);
offline.addActionListener(al); // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(720, 400);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((d.width - 720) / 2, (d.height - 400) / 2);
setVisible(true); new Thread() {
public void run() {
try {
// 在2221端口接收服务器发送过来的聊天内容,包括上线,下线消息。
DatagramSocket rSocket = new DatagramSocket(2220);
while (true) {
byte[] buffer = new byte[1024 * 16];
DatagramPacket recvPacket = new DatagramPacket(buffer, buffer.length);
rSocket.receive(recvPacket);
byte[] data = recvPacket.getData();
byte[] recvData = new byte[recvPacket.getLength()];
System.arraycopy(buffer, 0, recvData, 0, recvData.length);
//将从服务器接收的数据存入Map并显示
Map<String, Object> map = convertByteArrayToMap(recvData);
if (map.containsKey("onlineFlag")) { // 上线或者下线
boolean b = (boolean) map.get("onlineFlag");
if (b) { // 上线
map.put("input", "上线");
} else { // 下线
map.put("input", "下线");
}
}
Date time = (Date) map.get("time");
String s = convertDateToFormatString(time);
String user = (String) map.get("username");
user = "[" + user + "]";
contents.append(s + user + ": " + (String) map.get("input") + "\r\n");
}
} catch (Exception e) {
e.printStackTrace();
} }
}.start(); } public String getServerAddress() {
String s = address.getText();
//trim删除多余空格
s = s.trim();
return s;
} public String getUsername() {
String s = username.getText();
s = s.trim();
if (s == null || s.length() == 0) {
s = "匿名";
}
return s;
} public String getInput() {
String s = input.getText();
s = s.trim();
if (s == null || s.length() == 0) {
s = "不想说什么";
}
return s;
} public static String convertDateToFormatString(Date d) {
return new java.text.SimpleDateFormat("(yyyy-MM-dd HH:mm:ss)").format(d);
} public static void send(String ip, int port, Map<String, Object> map) {
try {
byte[] data = convertMapToByteArray(map);
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(data, data.length); packet.setSocketAddress(new InetSocketAddress(ip, port));
socket.send(packet); } catch (Exception e) {
e.printStackTrace();
} } public static byte[] convertMapToByteArray(Map<String, Object> map) {
try {
//完成此代码块,要求将map集合中的数据转换成字节数组 ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream ois = new ObjectOutputStream(b);
ois.writeObject(map);
byte[] temp = b.toByteArray();
return temp; } catch (Exception e) {
e.printStackTrace();
}
return null;
} public static Map<String, Object> convertByteArrayToMap(byte[] data) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Map<String, Object> result = (Map<String, Object>) ois.readObject();
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
} public static void main(String[] args) {
new ChatClient();
} }
服务端代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress; import java.util.*;
import java.util.concurrent.LinkedBlockingQueue; public class ChatServer { LinkedBlockingQueue<Map<String, Object>> queue = new LinkedBlockingQueue<Map<String, Object>>();
Set<String> onlineIPs = new HashSet<String>(); // 当前在线IP。 public ChatServer() {
try { new Thread() {
public void run() {
while (true) {
try {
//补齐程序,要求从接收队列中取出数据,遍历在线IP集合,向所有在线IP发送数据 if( !queue.isEmpty() ){
if( !onlineIPs.isEmpty() ){
for(String ip : onlineIPs){
//下面的端口号可以自定义增加,初始转发至2220端口 多增加的端口可以实现本机内的广播
ChatClient.send(ip, 2221, queue.peek() );
ChatClient.send(ip, 2220, queue.remove() );
}
}
} //end
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
//接受端口2222
DatagramSocket serverSocket = new DatagramSocket(2222);
System.out.println("Chat Server started.");
while (true) {
byte[] buffer = new byte[1024 * 16];
DatagramPacket recvPacket = new DatagramPacket(buffer, buffer.length); serverSocket.receive(recvPacket); InetSocketAddress remoteAddress = new InetSocketAddress(recvPacket.getAddress(),
recvPacket.getPort());
System.out.println("接收到 " + remoteAddress.getHostString() + " 发送过来的数据包"); byte[] data = recvPacket.getData();
byte[] recvData = new byte[recvPacket.getLength()];
System.arraycopy(buffer, 0, recvData, 0, recvData.length);
System.out.println(recvData.length);
Map<String, Object> map = ChatClient.convertByteArrayToMap(recvData);
System.out.print("map长度"+map.size());
if (map.containsKey("onlineFlag")) { // 上线或者下线
boolean b = (boolean) map.get("onlineFlag");
if (b) { // 上线
onlineIPs.add(remoteAddress.getHostString());
} else { // 下线
onlineIPs.remove(remoteAddress.getHostString());
}
} queue.add(map); } } catch (Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new ChatServer(); } }
[java]基于UDP的Socket通信Demo的更多相关文章
- JAVA基础知识之网络编程——-基于UDP协议的通信例子
UDP是一种不可靠的协议,它在通信两端各建立一个socket,这两个socket不会建立持久的通信连接,只会单方面向对方发送数据,不检查发送结果. java中基于UDP协议的通信使用DatagramS ...
- 基于TCP和UDP的Socket通信
TCP的Socket通信 TCP是面向连接的,安全的协议,它是一对一的关系 server client 上面只是单个客户端同服务器通信,可使用多线程编程实现多个客户端的通信 UDP的Socket通信 ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
- TCP、UDP、Socket 通信(原)
说明:本随笔主要演示自己给自己发送消息例子,分别使用了TCP协议.UDP协议以及socket套接字通信.使用socket套接字了模拟TCP.UDP通信实现原理.其中有些源码都来自<C#高级编程 ...
- 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- java和C#之间SOCKET通信的问题
转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...
- Java和C#的socket通信相关(转)
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- Java进阶(四十七)Socket通信
Java进阶(四十七)Socket通信 今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...
- 基于android的Socket通信
一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...
随机推荐
- 「小程序JAVA实战」小程序的组件(23)
转自:https://idig8.com/2018/08/11/xiaochengxu-chuji-23/ 开始了解下小程序的组件.源码:https://github.com/limingios/wx ...
- 「小程序JAVA实战」小程序视图之条件判断(15)
转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-15/ 小程序里面也是有条件判断的,我相信大家在开发java if和jstl c:if c:when ...
- Please specify exact device preset UUID
Please specify exact device preset UUID 重启RAD IDE,重新选择 IOS Simulator ,iphone 机型!
- c++可变参数(示例)
#include "stdafx.h" #include <stdarg.h> // 必须包含的头文件 #define ADD(int_params,...) Add( ...
- Django框架开发web网站的网页优化—页面静态化
网站优化-页面静态化 1)概念 提前将页面所用到的数据从数据库查询出来,然后生成一个静态页面,之后用户来访问的时候,直接返回静态页面. 举例:首页静态化:获取首页用到的数据表中的数据,生成静态首页in ...
- A* 算法求第k短路径
A*算法是一类贪心算法,其可以用于寻找最优路径.我们可以利用A*算法来求第k短路径. 一条路径可以由两部分组成,第一部分是一个从出发到达任意点的任意路径,而第二部分是从第一部分的末端出发,到终点的最短 ...
- 01-nginx介绍及编译安装
第一天的时候学过apache,nginx和apache一样都是一个WEB服务器.也就是说你的网站之所以可以在网上运行,总得有一台机器在为你提供服务,这台机器就是服务器.这台服务器通过什么软件在为你提供 ...
- 34. Search for a Range (Array; Divide-and-Conquer)
Given a sorted array of integers, find the starting and ending position of a given target value. You ...
- MobileMovieTexture播放视频
MobileMovieTexture插件支持IOS系统播放视频文件.简单,方便
- jquery入门 动态调整div大小,使其宽度始终为浏览器宽度
有时候我们需要设置宽度为整个浏览器宽度的div,当然我们可以使用相对布局的方式做到这一点,不过我们也可以用jquery来实现. <!doctype html> <html> & ...