1 说明
最近获得了一个需求,要求是编写一个程序用于接收传递过来的XML字符串,将该字符串保存为指定目录下的xml文件并记录日志。为了提高传输效率,我才用了UDP协议来编写程序,本文主要讲解用SpringBoot框架编写UDP服务端程序,并编写了一个用于测试的客户端程序。
1.1 UDP 的主要特点
- UDP 是无连接的,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延
- UDP 使用尽最大努力交付,即不保证可靠交付,主机不需要维持复杂的连接状态表
- UDP 是面向报文的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界
- UDP 没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的
- UDP 支持一对一、一对多、多对一和多对多的交互通信
- UDP 的首部开销小,只有8个字节,比 TCP 的20个字节的首部要短
1.2 存在的问题
- 某些实时应用需要使用没有拥塞控制的 UDP,但很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,导致大家都无法正常接收。
- 还有一些使用 UDP 的实时应用,需要对 UDP 的不可靠传输进行适当的改进,以减少数据的丢失。应用进程可以在不影响应用的实时性的前提下,增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文
2 服务端编写示例
代码清单:
- UdpConfig.java
- FileXmlServer.java
- MsgEntity.java
1 UdpConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.ip.udp.UnicastReceivingChannelAdapter;
/**
* UDP配置
*
* @author 一朝风月
* @date 2021/12/16 14:54
*/
@Configuration
public class UdpConfig {
@Bean
public IntegrationFlow integrationFlow() {
return IntegrationFlows.from(new UnicastReceivingChannelAdapter(12345))
.handle("FileXmlServer", "handleMessage")
.get();
}
}
2 FileXmlServer.java
import com.alibaba.fastjson.JSON;
import com.css.filexml.model.MsgEntity;
import com.css.filexml.utils.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Xml报文存储服务
*
* @author 一朝风月
* @date 2021/12/16 14:59
*/
@Service("FileXmlServer")
@Slf4j
public class FileXmlServer {
/**
* 文件存储路径
*/
@Value("${filePath}")
private String filePath;
/**
* 日志路径
*/
@Value("${logPath}")
private String logPath;
/**
* 日志文件名
*/
@Value("${logFileName}")
private String logFileName;
/**
* 处理消息
*
* @param message 消息
*/
public void handleMessage(Message message) {
String data = new String((byte[]) message.getPayload());
// SendMsg msg = JSON.parseObject(data, SendMsg.class);
MsgEntity msg = JSON.parseObject(data, MsgEntity.class);
String filePathName = filePath + File.separator + msg.getUuid() + ".xml";
XMLUtil.convertToXml(msg, filePathName);
File fileOk = new File(filePathName + ".ok");
if (new File(filePathName).exists()) {
XMLUtil.convertToXml(msg, fileOk.getPath());
}
try {
printLog(JSON.toJSONString(msg));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 记录日志
*
* @param msg 消息
* @throws IOException 异常
*/
private void printLog(String msg) throws IOException {
File filePath = new File(logPath);
if (!filePath.exists()) {
filePath.mkdirs();
new File(logPath + File.separator + logFileName).createNewFile();
}
BufferedWriter out = new BufferedWriter(new FileWriter(logPath + File.separator + logFileName, true));
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
out.write(currentTime + "\t" + msg + "\n");
out.close();
}
}
3 MsgEntity.java
/**
* 消息内容实体类
*
* @author 一朝风月
* @date 2021/12/21 11:44
*/
public class MsgEntity {
/**
* UUID
*/
private String uuid;
/**
* 字段1
*/
private String msg1;
/**
* 字段2
*/
private String msg2;
/**
* 字段3
*/
private String msg3;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getMsg1() {
return msg1;
}
public void setMsg1(String msg1) {
this.msg1 = msg1;
}
public String getMsg2() {
return msg2;
}
public void setMsg2(String msg2) {
this.msg2 = msg2;
}
public String getMsg3() {
return msg3;
}
public void setMsg3(String msg3) {
this.msg3 = msg3;
}
}
3 测试程序
3.1 例程
1 FileXmlClient.java
import com.alibaba.fastjson.JSON;
import com.css.filexml.model.MsgEntity;
import org.springframework.integration.ip.udp.UnicastSendingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
/**
* 客户端
*
* @author 一朝风月
* @date 2021/12/16 20:06
*/
public class FileXmlClient {
private String host;
private Integer port;
public FileXmlClient(String host, Integer port) {
this.host = host;
this.port = port;
}
public void send(MsgEntitysendMsg) {
UnicastSendingMessageHandler handler =
new UnicastSendingMessageHandler(host, port);
String payload = JSON.toJSONString(sendMsg);
handler.handleMessage(MessageBuilder.withPayload(payload).build());
}
}
2 Test.java
import com.css.filexml.client.FileXmlClient;
import com.css.filexml.model.MsgEntity;
/**
* 测试程序
*
* @author 一朝风月
* @date 2021/12/16 15:07
*/
public class Test {
public static void main(String[] args) {
FileXmlClient fileXmlClient = new FileXmlClient("127.0.0.1", 12345);
MsgEntity msgEntity = new MsgEntity();
msgEntity.setUuid("1234567890");
fileXmlClient.send(msgEntity);
}
}
3.2 测试结果
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<msgEntity>
<uuid>1234567890</uuid>
</msgEntity>
2021-12-21 12:03:40.973 {"uuid":"1234567890"}