<!-- 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>
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();
}
}
}
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;
}
}
#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
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
下一节讲解 摄像头注册