以下僅代表個人了解,僅供參考,歡迎大佬糾正!!!
maven依賴
<!-- springboot配置依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.38.Final</version>
</dependency>
SipUdpServer 服務類
import com.fengyulei.fylsipserver.config.ConfigInfo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
//整合springboot 直接單例注入
@Component
public class SipUdpServer implements Runnable{
private static final Logger logger = LoggerFactory.getLogger(SipUdpServer.class);
//配置類注入
@Autowired
private ConfigInfo configInfo;
//udp伺服器可以使用單例Handler,友善其他類注入
@Autowired
private SipServerHandler sipServerHandler;
@PostConstruct
private void init(){
//異步啟動netty 不使用異步會阻塞程式
Thread thread=new Thread(this);
thread.setDaemon(true);
thread.setName("sip server netty thread");
thread.start();
}
@Override
public void run(){
EventLoopGroup bossGroup=new NioEventLoopGroup();
try{
//通過NioDatagramChannel建立Channel,并設定Socket參數支援廣播
//UDP相對于TCP不需要在用戶端和服務端建立實際的連接配接,是以不需要為連接配接(ChannelPipeline)設定handler
Bootstrap b=new Bootstrap();
b.group(bossGroup)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(sipServerHandler);
ChannelFuture channelFuture=b.bind(configInfo.getServerPort()).sync();
sipServerHandler.setChannelFuture(channelFuture);
logger.info("SipUdpServer 啟動成功 ip:[{}],port:[{}]",configInfo.getServerIp(),configInfo.getServerPort());
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
logger.error(e.getMessage(),e);
}finally{
bossGroup.shutdownGracefully();
}
}
}
ConfigInfo 配置類
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
@Validated
@Component
@ConfigurationProperties(prefix = "fyl.sip")
public class ConfigInfo {
@NotEmpty(message = "serverId 不能為空")
private String serverId;
private Integer serverPort=5060;
private String serverIp="0.0.0.0";
@NotEmpty(message = "mediaServerIp 不能為空")
private String mediaServerIp;
@NotEmpty(message = "mediaServerPort 不能為空")
private String mediaServerPort;
@NotEmpty(message = "sipDeviceKey 不能為空")
private String sipDeviceKey;
private Integer mediaUdpTcpServerPort;
public Integer getMediaUdpTcpServerPort() {
return mediaUdpTcpServerPort;
}
public void setMediaUdpTcpServerPort(Integer mediaUdpTcpServerPort) {
this.mediaUdpTcpServerPort = mediaUdpTcpServerPort;
}
public String getSipDeviceKey() {
return sipDeviceKey;
}
public void setSipDeviceKey(String sipDeviceKey) {
this.sipDeviceKey = sipDeviceKey;
}
public String getServerId() {
return serverId;
}
public void setServerId(String serverId) {
this.serverId = serverId;
}
public Integer getServerPort() {
return serverPort;
}
public void setServerPort(Integer serverPort) {
this.serverPort = serverPort;
}
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
}
public String getMediaServerIp() {
return mediaServerIp;
}
public void setMediaServerIp(String mediaServerIp) {
this.mediaServerIp = mediaServerIp;
}
public String getMediaServerPort() {
return mediaServerPort;
}
public void setMediaServerPort(String mediaServerPort) {
this.mediaServerPort = mediaServerPort;
}
}
application.properties 配置資訊
#sip伺服器id
fyl.sip.server-id=34020000002000000001
#sip伺服器ip位址,預設為0.0.0.0即可
fyl.sip.server-ip=0.0.0.0
#sip伺服器監聽的端口号
fyl.sip.server-port=5060
#接收流媒體的ip
fyl.sip.media-server-ip=192.168.1.201
#接收流媒體的端口,改端口同時監聽udp和tcp 直接發到第三方伺服器端口
fyl.sip.media-server-port=10000
#儲存攝像頭裝置資訊的redis key
fyl.sip.sip-device-key=fyl_sip_device_key
#接收流媒體的端口,改端口同時監聽udp和tcp 該端口用于自己接收rtp ps流
fyl.sip.media-udp-tcp-server-port=10002
SipServerHandler 簡單實作
package com.fengyulei.fylsipserver.netty;
import com.fengyulei.fylsipserver.config.ConfigInfo;
import com.fengyulei.fylsipserver.data.Data;
import com.fengyulei.fylsipserver.data.SendDataTask;
import com.fengyulei.fylsipserver.data.SendTipsTask;
import com.fengyulei.fylsipserver.entity.DeviceInfo;
import com.fengyulei.fylsipserver.service.CommonService;
import com.fengyulei.fylsipserver.util.Utils;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//udp直接單例注入
@Component
public class SipServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static final Logger logger= LoggerFactory.getLogger(SipServerHandler.class);
//udp通道 備用
private Channel channel;
private ChannelFuture channelFuture;
public ChannelFuture getChannelFuture() {
return channelFuture;
}
public void setChannelFuture(ChannelFuture channelFuture) {
this.channelFuture = channelFuture;
setChannel(channelFuture.channel());
}
//一下屬性參考配置檔案
private static String serverIp=null;
private static String serverPort=null;
private static String serverId=null;
private static String mediaServerIp=null;
private static String mediaServerPort=null;
private void setChannel(Channel channel) {
if(channel==null){
logger.error("channel null");
System.exit(1);
}
this.channel = channel;
}
//配置類
@Autowired
private ConfigInfo configInfo;
//redis
@Resource(name = "FylSipRedisTemplate")
private RedisTemplate redisTemplate;
//業務處理類 可忽略
@Autowired
private CommonService commonService;
private void setDeviceInfo(String deviceId, DeviceInfo deviceInfo){
redisTemplate.opsForHash().put(configInfo.getSipDeviceKey(),deviceId,deviceInfo);
}
private DeviceInfo getDeviceInfo(String deviceId){
Object obj=redisTemplate.opsForHash().get(configInfo.getSipDeviceKey(),deviceId);
if(obj==null){
return null;
}
return (DeviceInfo)obj;
}
//初始化配置
@PostConstruct
private void init(){
serverIp=configInfo.getServerIp();
serverPort=configInfo.getServerPort().toString();
serverId=configInfo.getServerId();
mediaServerIp=configInfo.getMediaServerIp();
//mediaServerPort=configInfo.getMediaServerPort();
mediaServerPort=configInfo.getMediaUdpTcpServerPort().toString();
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket packet) throws Exception {
//建議捕獲異常,防止程式異常退出
try {
//gbk解碼
String str=packet.content().toString(Charset.forName("gbk"));
//去除空包,公網狀态下很多空包 應該是伺服器端口被探測
if(str.trim().length()==0){
return;
}
//列印接收資訊
//logger.info("-------------");
//logger.info(n+str);
//logger.info(packet.sender().getAddress().getHostAddress());
//logger.info(String.valueOf(packet.sender().getPort()));
//logger.info("-------------");
}catch (Exception e){
logger.error(e.getMessage(),e);
//throw e;
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws Exception{
//關閉之後會導緻netty不可用,udp是單通道的 盡量防止異常抛到這裡
ctx.close();
logger.error(cause.getMessage(),cause);
}
//發送udp資料包 注意gbk編碼
private void send(String sendStr,InetSocketAddress inetSocketAddress){
channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(sendStr,Charset.forName("gbk")), inetSocketAddress));
}
}
udp伺服器搭建到這結束,不懂的直接留言提問 或滴滴QQ:738126916
下一節講解 攝像頭注冊