JavaDemo——Jain Sip摘要认证

JAIN SIP API详解与GB28181服务器实现【保姆级源码教程】 这篇文章展示了基于Java SE如何创建客户端侧的SIP应用。JAIN SIP API是一个强大的“SIP协议栈”。本文将通过一个简单的即时通讯程序以及一个GB28181协议的简单应用程序,详细的分析该技术。 详细的代码说明,SIP学习一眼便会!玩转Java信令服务器的开发,玩转Java音视频,玩转融合通信! 阅读详情
AI摘要

本文详细解析SIP协议的认证流程,包括客户端和服务端交互过程,并通过JAIN SIP实现SIP协议的注册功能。展示了如何使用maven导入相关依赖,以及如何在服务端和客户端进行SIP消息的构造和处理。

maven导入:

<!-- https://mvnrepository.com/artifact/javax.sip/jain-sip-ri -->
	<dependency>
	    <groupId>javax.sip</groupId>
	    <artifactId>jain-sip-ri</artifactId>
	    <version>1.3.0-91</version>
	    <scope>provided</scope>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/log4j/log4j -->
	<dependency>
	    <groupId>log4j</groupId>
	    <artifactId>log4j</artifactId>
	    <version>1.2.17</version>
	</dependency>

认证流程:

1.客户端向服务端发送Register请求;

2.服务端返回401并带有WWW-Authenticate头消息;

3.客户端根据WWW-Authenticate里的信息做摘要认证,生成Authorization头消息并添加,再次发送Register;

4.服务端根据收到的Authorization头消息验证,返回200 OK结果;

WWW-Authenticate: Digest realm="xx",qop="auth,auth-int",nonce="xx",opaque="xx"
Authorization: Digest username="xx",realm="xx",qop="auth",nonce="xx",uri="path",cnonce="xx",nc=00000001,response="xx",opaque="xx"

摘要公式(MD5为例):

response=MD5(HA1:HD:HA2)

注:algorithm为MD5或者MD5-sess或者未定义,都是MD5算法;string类型字段加密时不带引号;

HA1定义:

1.如果algorithm是MD5或者未定义,则:

HA1=username:realm:password

2.如果algorithm是MD5-sess,则:

HA1=username:realm:password:nonce:cnonce

HA2定义:

1.如果qop是auth或者未定义,则:

HA2=Method:uri

2.如果qop是auth-int,则:

HA2=Method:uri:MD5(包体)

HD定义:

1.如果qop有值auth或者auth-int,则:

HD=nonce:nc:cnonce:qop

2.如果qop未定义,则:

HD=nonce

 

服务端Demo:

/**
 * 2018年12月13日下午2:55:40
 */
package testJainSip;

import java.text.ParseException;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Set;
import java.util.TooManyListenersException;

import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogTerminatedEvent;
import javax.sip.IOExceptionEvent;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.PeerUnavailableException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.SipListener;
import javax.sip.SipProvider;
import javax.sip.SipStack;
import javax.sip.TimeoutEvent;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.TransportNotSupportedException;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.DateHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.ToHeader;
import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;

import gov.nist.javax.sip.header.AuthenticationHeader;

/**
 * @author XWF
 *
 */
public class JainSipServer implements SipListener{
	SipStack sipstack = null;
	HeaderFactory hf = null;
	AddressFactory af = null;
	MessageFactory mf = null;
	SipProvider sipProvider = null;
	
	/**
	 * 保存正在注册的用户,注册第一步的
	 */
	private static Set<String> registingId = new HashSet<>();
	/**
	 * 保存当前注册的用户,注册成功的
	 */
	private static Hashtable<String, URI> registedContactURI = new Hashtable<>();
	
	public static void main(String[] args) {
		JainSipServer test = new JainSipServer();
		test.init();
	}
	public void init() {
		Properties prop = new Properties();
		prop.setProperty("javax.sip.STACK_NAME", "teststackname");
//		prop.setProperty("javax.sip.IP_ADDRESS", "127.0.0.1");
//		prop.setProperty("javax.sip.OUTBOUND_PROXY", "127.0.0.1:8888/UDP");
		// You need 16 for logging traces. 32 for debug + traces.
		// Your code will limp at 32 but it is best for debugging.
		prop.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
		prop.setProperty("gov.nist.javax.sip.DEBUG_LOG", "siptestdebug.txt");
		prop.setProperty("gov.nist.javax.sip.SERVER_LOG", "siptestlog.txt");
		
		SipFactory sf = SipFactory.getInstance();
		sf.setPathName("gov.nist");
		try {
			sipstack = sf.createSipStack(prop);
		} catch (PeerUnavailableException e) {
			e.printStackTrace();
		}
		
		try {
			hf = sf.createHeaderFactory();
			af = sf.createAddressFactory();
			mf = sf.createMessageFactory();
			ListeningPoint listeningPoint = sipstack.createListeningPoint("192.168.1.30", 5060, "udp");
			
			sipProvider = sipstack.createSipProvider(listeningPoint);
			sipProvider.addSipListener(this);
			System.out.println("服务启动完成。。。");
		} catch (TransportNotSupportedException e) {
			e.printStackTrace();
		} catch (InvalidArgumentException e) {
			e.printStackTrace();
		} catch (TooManyListenersException e) {
			e.printStackTrace();
		} catch (ObjectInUseException e) {
			e.printStackTrace();
		} catch (PeerUnavailableException e) {
			e.printStackTrace();
		}
		
	}

	
	//Listener实现
	@Override
	public void processRequest(RequestEvent requestEvent) {
		Request request = requestEvent.getRequest();
		if(null == request) {
			System.out.println("收到的requestEvent.getRequest() is null.");
			return ;
		}
		
		System.out.println(">>>>>收到的request内容是\n"+request);
		
		switch(request.getMethod().toUpperCase()){
		case Request.INVITE:
			System.out.println("收到INVITE的请求");
			break;
		case Request.REGISTER:
			System.out.println("收到REGISTER的请求");
			doRegister(request,requestEvent);
			break;
		case Request.SUBSCRIBE:
			System.out.println("收到SUBSCRIBE的请求");
			break;
		case Request.ACK:
			System.out.println("收到ACK的请求");
			break;
		case Request.BYE:
			System.out.println("收到BYE的请求");
			break;
		case Request.CANCEL:
			System.out.println("收到CANCEL的请求");
			break;
		default:
			System.out.println("不处理的requestMethod:"+request.getMethod().toUpperCase());
		}
	}

	@Override
	public void processResponse(ResponseEvent responseEvent) {
		Response response = responseEvent.getResponse();
		if(null == response) {
			System.out.println("response is null.");
			return ;
		}
		System.out.println("收到的Response is :"+response);
		ClientTransaction clientTransaction = responseEvent.getClientTransaction();
		Request request = clientTransaction.getRequest();
		System.out.println("收到的Response for request:"+request);
		
		if(response.getStatusCode() == Response.TRYING) {
			System.out.println("收到的response is 100 TRYING");
			return ;
		}
		switch(request.getMethod().toUpperCase()) {
		case Request.INVITE:
			System.out.println("收到INVITE的响应");
			break;
		case Request.BYE:
			System.out.println("收到BYE的响应");
			break;
		case Request.CANCEL:
			System.out.println("收到CANCEL的响应");
			break;
		default:
			System.out.println("不处理的response的请求类型:"+request.getMethod().toUpperCase());
		}
	}

	@Override
	public void processTimeout(TimeoutEvent timeoutEvent) {
		// TODO Auto-generated method stub
	}

	@Override
	public void processIOException(IOExceptionEvent exceptionEvent) {
		// TODO Auto-generated method stub
	}

	@Override
	public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
		// TODO Auto-generated method stub
	}

	@Override
	public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
		// TODO Auto-generated method stub
	}
	
	private void doRegister(Request request, RequestEvent requestEvent) {
		if(null == request || null == requestEvent) {
			System.out.println("无法处理REGISTER请求,request="+request+",event="+requestEvent);
			return ;
		}
		ServerTransaction serverTransactionId = requestEvent.getServerTransaction();
		try {
			Response response = null;
			
			ToHeader toHead = (ToHeader) request.getHeader(ToHeader.NAME);
			Address toAddress = toHead.getAddress();
			URI toURI = toAddress.getURI();
			SipURI sipURI_to = (SipURI) toURI;
			String toUserId = sipURI_to.getUser();
			System.out.println("注册的toUserId是"+toUserId);
			
			ContactHeader contactHeader = (ContactHeader) request.getHeader(ContactHeader.NAME);
			Address contactAddr = contactHeader.getAddress();
			URI contactURI = contactAddr.getURI();
			
			System.out.println("注册 from: " + toURI + " request str: " + contactURI);
			if(null == toUserId || "".equals(toUserId)) {
				System.out.println("无法识别的userId,不处理。");
				return ;
			}
			int expires = request.getExpires().getExpires();
			// 如果expires不等于0,则为注册,否则为注销。
			if (expires != 0 || contactHeader.getExpires() != 0) {//注册
				if(registedContactURI.containsKey(toUserId)) {//已经注册了
					System.out.println("已经注册过了 user=" + toURI);
				}else {//不是注册成功状态
					if(registingId.contains(toUserId)) {//是第二次注册
						System.out.println("第二次注册 register user=" + toURI);
						// 验证AuthorizationHeader摘要认证信息
						AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
						boolean authorizationResult = false;
						if(null != authorizationHeader) {//验证
							String username = authorizationHeader.getUsername();
							String realm = authorizationHeader.getRealm();
							String nonce = authorizationHeader.getNonce();
							URI uri = authorizationHeader.getURI();
							String res = authorizationHeader.getResponse();
							String algorithm = authorizationHeader.getAlgorithm();
							System.out.println("Authorization信息:username="+username+",realm="+realm+",nonce="+nonce+",uri="+uri+",response="+res+",algorithm="+algorithm);
							if(null==username || null==realm || null==nonce || null==uri || null==res || null==algorithm) {
								System.out.println("Authorization信息不全,无法认证。");
							}else {
								// 比较Authorization信息正确性
								String A1 = MD5Util.MD5(username+":"+realm+":12345678");
								String A2 = MD5Util.MD5("REGISTER:sip:servername@192.168.1.30:5060");
								String resStr = MD5Util.MD5(A1+":"+nonce+":"+A2);
								if(resStr.equals(res)) {
									//注册成功,标记true
									authorizationResult = true;
								}
							}
						}
						registingId.remove(toUserId);//不管第二次是否成功都移除,失败要从头再来
						// 验证成功加入成功注册列表,失败不加入
						if(authorizationResult) {//注册成功
							System.out.println("注册成功?");
							registedContactURI.put(toUserId, contactURI);
							//返回成功
							response = mf.createResponse(Response.OK, request);
							DateHeader dateHeader = hf.createDateHeader(Calendar.getInstance());
							response.addHeader(dateHeader);
							System.out.println("返回注册结果 response是\n" + response.toString());

							if (serverTransactionId == null) {
								serverTransactionId = sipProvider.getNewServerTransaction(request);
								serverTransactionId.sendResponse(response);
								// serverTransactionId.terminate();
//								System.out.println("register serverTransaction: " + serverTransactionId);
							} else {
								System.out.println("processRequest serverTransactionId is null.");
							}
						}else {//注册失败
							System.out.println("注册失败?");
							//返回失败
							response = mf.createResponse(Response.FORBIDDEN, request);
							System.out.println("返回注册结果 response是\n" + response.toString());

							if (serverTransactionId == null) {
								serverTransactionId = sipProvider.getNewServerTransaction(request);
								serverTransactionId.sendResponse(response);
							} else {
								System.out.println("processRequest serverTransactionId is null.");
							}
						}
					}else {//是第一次注册
						System.out.println("首次注册 user=" + toURI);
						// 加入registing列表
						registingId.add(toUserId);
						//发送响应
						response = mf.createResponse(Response.UNAUTHORIZED, request);
						String realm = "zectec";
						CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
						String callId = callIdHeader.getCallId();
						String nonce = MD5Util.MD5(callId+toUserId);
						WWWAuthenticateHeader wwwAuthenticateHeader = hf.createWWWAuthenticateHeader("Digest realm=\""+realm+"\",nonce=\""+nonce+"\"");
						response.setHeader(wwwAuthenticateHeader);
						System.out.println("返回注册结果 response是\n" + response.toString());

						if (serverTransactionId == null) {
							serverTransactionId = sipProvider.getNewServerTransaction(request);
							serverTransactionId.sendResponse(response);
							// serverTransactionId.terminate();
//							System.out.println("register serverTransaction: " + serverTransactionId);
						} else {
							System.out.println("processRequest serverTransactionId is null.");
						}
						
					}
				}
			} else {//注销
				System.out.println("注销 user=" + toURI);
				//发送ok响应
				response = mf.createResponse(Response.OK, request);
				System.out.println("返回注销结果 response  : " + response.toString());
				if (serverTransactionId == null) {
					serverTransactionId = sipProvider.getNewServerTransaction(request);
					serverTransactionId.sendResponse(response);
					// serverTransactionId.terminate();
					System.out.println("register serverTransaction: " + serverTransactionId);
				} else {
					System.out.println("processRequest serverTransactionId is null.");
				}
				//移除
				registingId.remove(toUserId);
				registedContactURI.remove(toUserId);
			}


		} catch (ParseException e) {
			e.printStackTrace();
		} catch (SipException e) {
			e.printStackTrace();
		} catch (InvalidArgumentException e) {
			e.printStackTrace();
		}
	}

}

客户端Demo:

package testJainSip;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import java.util.TooManyListenersException;

import javax.sip.Dialog;
import javax.sip.DialogTerminatedEvent;
import javax.sip.IOExceptionEvent;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.PeerUnavailableException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.SipListener;
import javax.sip.SipProvider;
import javax.sip.SipStack;
import javax.sip.TimeoutEvent;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.TransportNotSupportedException;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.DateHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.Header;
import javax.sip.header.HeaderFactory;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;

public class JainSipClient {
	
	private SipStack sipStack;

	private SipFactory sipFactory;

	private AddressFactory addressFactory;

	private HeaderFactory headerFactory;

	private MessageFactory messageFactory;

	private SipProvider sipProvider;
	
	private Dialog dialog;

	String ip = "192.168.1.30";
	int port = 5061;
	String uname="Tom";
	
	public static void main(String[] args) {
		JainSipClient client = new JainSipClient();
		client.init();
		client.sendMessage("Tom","192.168.1.30:5061","Tom","192.168.1.30:5061","");
	}

	public void init(){
		try {
			Properties prop = new Properties();
			prop.setProperty("javax.sip.STACK_NAME", "teststackname");
			prop.setProperty("javax.sip.IP_ADDRESS", ip);
			prop.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
			prop.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sipclientdebug.txt");
			prop.setProperty("gov.nist.javax.sip.SERVER_LOG", "sipclientlog.txt");
			
			sipFactory = SipFactory.getInstance();
			sipFactory.setPathName("gov.nist");
			
			sipStack = sipFactory.createSipStack(prop);
			
			headerFactory = sipFactory.createHeaderFactory();
			addressFactory = sipFactory.createAddressFactory();
			messageFactory = sipFactory.createMessageFactory();
			
			ListeningPoint listeningpoint_udp =sipStack.createListeningPoint(port, "udp");
//			ListeningPoint listeningponit_tcp =sipStack.createListeningPoint(port, "tcp");
			
			sipProvider = sipStack.createSipProvider(listeningpoint_udp);
			ClientListener listener = new ClientListener(addressFactory,headerFactory,messageFactory,sipProvider);
			sipProvider.addSipListener(listener);
//			sipProvider = sipStack.createSipProvider(listeningponit_tcp);
//			sipProvider.addSipListener(listener);
			System.out.println("client init finished.");
		} catch (PeerUnavailableException | TransportNotSupportedException | ObjectInUseException
				| InvalidArgumentException | TooManyListenersException e) {
			e.printStackTrace();
		}
		
	}
	public void sendMessage(String fromUserName,String fromIpPort,String toUserName,String toIpPort,String message){
		try {
			//requestURI
			SipURI requestSipURI = addressFactory.createSipURI("gov.nist","192.168.1.30:5060");
			requestSipURI.setTransportParam("udp");
			//from
			SipURI fromSipURI = addressFactory.createSipURI(fromUserName, fromIpPort);
			Address fromAddress = addressFactory.createAddress(fromSipURI);
			fromAddress.setDisplayName("a");
			FromHeader fromHeader = headerFactory.createFromHeader(fromAddress,"mytag");
			//to
			SipURI toSipURI = addressFactory.createSipURI(toUserName, toIpPort); 
			Address toAddress = addressFactory.createAddress(toSipURI);
			toAddress.setDisplayName("b");
			ToHeader toHeader = headerFactory.createToHeader(toAddress,null);
			//via
			ViaHeader viaHeader = headerFactory.createViaHeader(ip, port, "udp", "branchingbranching");
			List<ViaHeader> viaHeaderList = new ArrayList<>();
			viaHeaderList.add(viaHeader);
			//callid,cseq,maxforwards
			CallIdHeader callIdHeader = sipProvider.getNewCallId();
			CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.REGISTER);
			MaxForwardsHeader maxForwardsHeader = headerFactory.createMaxForwardsHeader(70);
			//
			Request request = messageFactory.createRequest(requestSipURI, Request.REGISTER, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaderList, maxForwardsHeader);
			//contact
			SipURI contactURI = addressFactory.createSipURI(fromUserName, fromIpPort);
			contactURI.setPort(port);
			Address  contactAddress = addressFactory.createAddress(contactURI);
			contactAddress.setDisplayName(uname);
			ContactHeader contactHeader = headerFactory.createContactHeader(contactAddress);
			request.addHeader(contactHeader);
			//expires
			ExpiresHeader expiresHeader = headerFactory.createExpiresHeader(3600);
			request.addHeader(expiresHeader);
			
//			ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("text","plain");
//			request.setContent(message,contentTypeHeader);
			
			System.out.println(request);
			sipProvider.sendRequest(request);
//			//
//			ClientTransaction trans = sipProvider.getNewClientTransaction(request);
//			dialog = trans.getDialog();
//			trans.sendRequest();
//			//
//			request = dialog.createRequest(Request.MESSAGE);
//			request.setHeader(contactHeader);
//			request.setContent(message, contentTypeHeader);
//			ClientTransaction ctrans = sipProvider.getNewClientTransaction(request);
//			ctrans.sendRequest();
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (InvalidArgumentException e) {
			e.printStackTrace();
		} catch (SipException e) {
			e.printStackTrace();
		}
	}
}

class ClientListener implements SipListener{
	private AddressFactory addressFactory;

	private HeaderFactory headerFactory;

	private MessageFactory messageFactory;

	private SipProvider sipProvider;
	
	public ClientListener(AddressFactory addressFactory, HeaderFactory headerFactory, MessageFactory messageFactory,
			SipProvider sipProvider) {
		super();
		this.addressFactory = addressFactory;
		this.headerFactory = headerFactory;
		this.messageFactory = messageFactory;
		this.sipProvider = sipProvider;
	}

	@Override
	public void processRequest(RequestEvent requestEvent) {
		System.out.println("processRequest执行");
		Request request = requestEvent.getRequest();
		if(null == request) {
			System.out.println("requestEvent.getRequest() is null.");
			return ;
		}
		
		System.out.println("request内容是\n"+request);
	}

	@Override
	public void processResponse(ResponseEvent responseEvent) {
		System.out.println("processResponse执行");
		Response response = responseEvent.getResponse();
		if(null == response) {
			System.out.println("response is null.");
			return ;
		}
		System.out.println("返回码:"+response.getStatusCode());
		System.out.println("Response is :"+response);
		WWWAuthenticateHeader wwwHeader = (WWWAuthenticateHeader) response.getHeader(WWWAuthenticateHeader.NAME);
		if(null != wwwHeader) {
			String realm = wwwHeader.getRealm();
			String nonce = wwwHeader.getNonce();
			String A1 = MD5Util.MD5("Tom:"+realm+":12345678");
			String A2 = MD5Util.MD5("REGISTER:sip:servername@192.168.1.30:5060");
			String resStr = MD5Util.MD5(A1+":"+nonce+":"+A2);
			
			try {
				//requestURI
				SipURI requestSipURI = addressFactory.createSipURI("gov.nist","192.168.1.30:5060");
				requestSipURI.setTransportParam("udp");
				//from
				SipURI fromSipURI = addressFactory.createSipURI("Tom", "192.168.1.30:5061");
				Address fromAddress = addressFactory.createAddress(fromSipURI);
				fromAddress.setDisplayName("a");
				FromHeader fromHeader = headerFactory.createFromHeader(fromAddress,"mytag2");
				//to
				SipURI toSipURI = addressFactory.createSipURI("Tom", "192.168.1.30:5061"); 
				Address toAddress = addressFactory.createAddress(toSipURI);
				toAddress.setDisplayName("b");
				ToHeader toHeader = headerFactory.createToHeader(toAddress,null);
				//via
				ViaHeader viaHeader = headerFactory.createViaHeader("192.168.1.30", 5061, "udp", "branchingbranching");
				List<ViaHeader> viaHeaderList = new ArrayList<>();
				viaHeaderList.add(viaHeader);
				//callid,cseq,maxforwards
				CallIdHeader callIdHeader = sipProvider.getNewCallId();
				CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(2L, Request.REGISTER);
				MaxForwardsHeader maxForwardsHeader = headerFactory.createMaxForwardsHeader(70);
				//
				Request request = messageFactory.createRequest(requestSipURI, Request.REGISTER, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaderList, maxForwardsHeader);
				//contant
				SipURI contantURI = addressFactory.createSipURI("Tom", "192.168.1.30:5061");
				contantURI.setPort(5061);
				Address  contantAddress = addressFactory.createAddress(contantURI);
				contantAddress.setDisplayName("abc");
				ContactHeader contactHeader = headerFactory.createContactHeader(contantAddress);
				request.addHeader(contactHeader);
				//expires
				ExpiresHeader expiresHeader = headerFactory.createExpiresHeader(3600);
				request.addHeader(expiresHeader);
				
				ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("text","plain");
				request.setContent("",contentTypeHeader);
				
				AuthorizationHeader aHeader = headerFactory.createAuthorizationHeader("Digest");
				aHeader.setUsername("Tom");
				aHeader.setRealm(realm);
				aHeader.setNonce(nonce);
				aHeader.setURI(fromSipURI);
				aHeader.setResponse(resStr);
				aHeader.setAlgorithm("MD5");
				request.addHeader(aHeader);
				
				System.out.println(request);
				sipProvider.sendRequest(request);
			} catch (ParseException | InvalidArgumentException | SipException e) {
				e.printStackTrace();
			}
			
		}
	}

	@Override
	public void processTimeout(TimeoutEvent timeoutEvent) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void processIOException(IOExceptionEvent exceptionEvent) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
		System.out.println("processTransactionTerminated执行");
	}

	@Override
	public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
		System.out.println("processDialogTerminated执行");
	}
	
}

结果:

 

 

参考:

https://www.oracle.com/technetwork/cn/articles/oem/introduction-jain-sip-090386-zhs.html

https://blog.youkuaiyun.com/gredn/article/details/72847197

https://www.cnblogs.com/wenjingu/p/4019434.html

https://blog.youkuaiyun.com/jszj/article/details/8918967?from=singlemessage

https://www.cnblogs.com/fengyv/archive/2013/02/05/2892729.html

一、基于JAVA的GB28181实现之SIP服务 GB28181定义了了 基于SIP架构的 视频监控互联规范,而对于多数私有协议实现的监控系统如果想接入SIP架构,就要借助网关,GB28181 规范了实现 SIP 监控域与非SIP 监控域互联。最近用JAVA的SIP协议写了一个GB28181平台的对接,并成功完成了海康、大华、中威等设备,更重要的是海康平台、公安一所平台的对接。因为行业内很少有JAVA方面的设备接入实现,希望本篇能够让JAVA在安防接入生态中发挥越来越大的作用。 阅读详情

相关推荐

Java开发者必看:GB28181 SIP服务实战指南(含海康/大华设备对接)

本文为Java开发者提供GB28181 SIP服务的实战指南,涵盖从基础架构搭建到与海康、大华等主流设备对接的详细步骤。通过JAIN SIP协议栈实现SIP服务器核心功能,解决设备注册、视频流传输等关键问题,助力开发者快速掌握安防系统集成技术。

i8j9k0l1的博客 222

JAIN SIP API 简介

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34221332的博客 1235

Sip协议(四) -注册流程

本文主要介绍下sip协议中, agent的注册流程.

赵航的博客 3046

【亲测免费】 推荐开源项目: Jain-SIP

推荐开源项目: Jain-SIP Jain-SIP 是一个开放源代码 Java API for SIP (Session Initiation Protocol) 和相关协议, 支持构建基于 IP 的语音、视频、即时消息和数据应用程序。 什么是Jain-SIP? Jain-SIP 是一个用于开发 VoIP 应用程序的 Java 框架, 它提供了一组接口和类来处理 SIP 协议的消息和事务。该框架支...

gitblog_00060的博客 1700

SpringBoot + JAIN-SIP 实战:手把手教你从零搭建国标GB28181摄像头管理后台

本文详细介绍了如何使用SpringBoot和JAIN-SIP协议栈从零搭建国标GB28181摄像头管理后台。通过核心组件介绍、SIP服务架构设计、设备管理与状态维护、视频流处理实战等步骤,帮助开发者快速构建企业级视频监控平台,实现设备注册、视频点播等功能,并提供了性能优化和安全注意事项。

weixin_26934905的博客 142

JAIN SIP协议栈实战与文档

JAIN SIP(Java API for Internet Networking - SIP),是SIP(Session Initiation Protocol)在Java环境下的应用程序接口,提供了一套标准的API来帮助开发者构建基于SIP的应用程序。JAIN SIP起源于电信行业,旨在为VoIP(Voice over IP)和其他实时通信服务提供一个统一的编程标准,它确保了不同厂商设备和服务之间的互操作性。

weixin_26854475的博客 932

jain-sip IPV6本地链路地址问题

在IPV6场景下,可以会使用到本地链路地址SIP协议中Via中这里的 %2 是一个百分号编码,表示IPv6接口ID。在SIP协议中,这是有效的写法。在一个不支持这种写法的系统或应用中看到这个格式,可能会引起问题。确保系统和应用支持这种格式或者考虑使用其他格式。jain-sip 协议栈不支持这种写法。包含了一系列的十六进制数字,并且使用冒号 “:” 进行分隔。前导的 “fe80::” 通常表示该地址属于本地链路地址范围。“%2” 是一个接口标识符,用于标识一个特定的网络接口。

xieqj_0511的博客 767

一个简单的JAVA-JAIN-SIP客户端,可以连接SIP服务端发起呼叫

包括登陆和发起呼叫流程

android-jain-sip-ri

android-jain-sip-ri的使用。国标28181。GB28181。

Android菜鸟的专栏 1430

SIP需要用到的四个包中的jain-sip-ri-1.2.295.jar

SIP需要用到的四个包:concurrent-1.3.4.jar,jain-sip-api-1.2.1.4.jar,jain-sip-ri-1.2.295.jar,log4j-1.2.8.jar

jain-sip-ri-1.2.277.jar

jain-sip-ri-1.2.277.jar,java调用sip协议需要用到。有需要的同学可以下载看看。

java 解析为sip_一、基于JAVA的GB28181实现之SIP服务启动[part1]

# 基于JAVA的SIP协议实现[part1]最近用JAVA的SIP协议写了一个GB28181平台的对接,并成功完成了海康、大华、中威等设备,更重要的是海康平台、公安一所平台的对接。因为行业内很少有JAVA方面的设备接入实现,希望本篇能够让JAVA在安防接入生态中发挥越来越大的作用。# 一、组件```javax.sipjain-sip-api1.2.1.4javax.sipjain-sip-ri...

weixin_39715907的博客 3773

jain-sip.rar_JAIN SIP ri1.2_between_jain_jain sip_sip

jain-sip is a protocol to comunicate between cliens throught service.

Jain-sip

 jain-sip 一些类的初步理解 1.javax.sip.ClientTransaction :ClientTransaction 应 用可以理解 为发 送 INVITE 信息到 UAS 。 ClientTransaction 也用从 SipListener 接收到的回 应进 行匹配。和 ServiceTransaction 相 对应 。方法:    ClientTrans

renxianzuo的专栏 2811

MS2107 CVBS转USB2.0 音视频采集芯片,支持1080P@30HZ输出

MS2107 是一款视频和音频采集芯片,支持CVBS转USB2.0 ;可以将 CVBS、S-Video 和音频信号通过 USB接口传送到 PC、智能手机和平板电脑上预览或采集。

TEL18967112838的博客 2076

龙迅LT9611UXC芯片简介:Dual-Port MIPI DSI/CSI to HDMI2.0 with Audio

龙迅半导体推出的LT9611UXC是一款高性能MIPI转HDMI2.0转换器,支持DSI/CSI接口转换,兼容多种视频格式(RGB/YCbCr),最高支持4K@60Hz输出。该芯片集成音频处理(I2S/SPDIF)、色彩空间转换和3D功能,适用于机顶盒、电视盒子等消费电子及车载设备。提供工业级(-40℃~+85℃)和车规级(AEC-Q100认证)版本,采用QFN64封装。

MB16698594834的博客 1334

Java 用JainSip实现服务器端SIP通讯----之监听篇

Java web服务器实现SIP通讯(或GB28181),一般有两种选择:SipServlet和JainSip 前者更适合服务器,后者较适合客户端 前者用类似web servlet的方式实现了sip通信,直接就实现了多线程的sip通信的并发 后者相对底层一点,不具有并发能力 但,前者需要Web容器的支持,目前好象能用的只有两三种,且与web servlet并存性好像也不好 故,考虑到要用

dongfangyu123456的博客 1万+

CANopen PDO 配置實戰:3步完成0x1800-0x1A00物件字典映射與事件觸發

本文详细解析CANopen PDO配置实战,通过3个关键步骤完成0x1800-0x1A00对象字典映射与事件触发设置。重点介绍COB-ID位域解析、映射参数配置及事件触发优化,帮助工程师实现工业自动化设备间毫秒级实时数据交换,提升系统通信效率。

weixin_33709609的博客 381

基于JAINSIP协议栈的一个简单SIP服务器实现流程

SIP服务器采用B2BUA,sip呼叫控制实现流程 TAG: SIP服务器采用B2BUA,sip呼叫控制实现流程:  INVITE的请求:  收到INVITE后,克隆INVITE消息。替换Request URI被叫注册的地址。  替换VIA头为服务器地址。通过该INVITE请求得到客户端事务并通过  该事务来发送INVITE请求。  180

gredn的专栏 1万+

AI大模型驱动Web UI自动化测试:Playwright与RobotFramework智能整合实践

Web自动化测试是软件质量保障的关键环节,其核心原理是通过脚本模拟用户操作,对Web应用界面进行功能验证。传统方法依赖固定的元素定位和脚本逻辑,在应对频繁的UI变更时面临维护成本高、脚本脆弱的挑战。随着AI大模型技术的发展,其强大的自然语言理解和代码生成能力为自动化测试带来了新的技术价值。通过将大模型的意图理解与代码生成能力,与Playwright强大的浏览器自动化执行引擎以及RobotFramework灵活的关键字驱动框架相结合,可以构建出能够理解自然语言指令、动态生成稳定操作脚本的智能测试系统。这种融合

weixin_28718769的博客 414

CASIA数据集解析:图像篡改检测的黄金标准与实践指南

本文深入解析了CASIA数据集在图像篡改检测领域的核心价值与应用实践。作为中科院自动化所打造的黄金标准,CASIA数据集通过模拟真实篡改场景(如拼接和复制移动)为研究者提供全面支持。文章详细对比了v1.0与v2.0版本差异,分享数据预处理和模型训练的最佳实践,并探讨了未来研究方向,是图像篡改检测领域的重要参考指南。

kappa的博客 785

JavaDemo——java使用RXTX读写串口

对RXTX的介绍,copy自https://blog.youkuaiyun.com/u011728105/article/details/48085615RXTX RXTX是一个提供串口和并口通信的开源java类库,由该项目发布的文件均遵循LGPL协议。 RXTX项目提供了Windows,Linux,Mac os X,Solaris操作系统下的兼容javax.comm串口通讯包API的实现,为其他开发人员...

FlyLikeButterfly的博客 1万+

使用 Java + PaddleOCR 实现表格识别,支持导出 HTML 和 Excel(附源码)

使用Java+PaddleOCR快速搭建表格识别系统,无需处理底层模型细节。系统支持表格结构识别和内容识别,可将图片转换为可编辑表格格式。文章提供了完整的实现流程,包括Maven依赖引入、模型下载(包含检测、识别、分类和表格结构模型)及参数配置说明。SmartJavaAI支持多种高性能模型选择,适用于不同应用场景,帮助开发者快速实现表格识别功能。

deng775747758的博客 1474
上一篇: MyBatis——mybatis基本搭建
下一篇: JavaDemo——jackson读写json和xml
FlyLikeButterfly
博客等级 码龄9年 223粉丝 209原创
评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值