SipSorcery注册与呼叫端口不一致致403问题及端口配置咨询
问题描述
我在Windows电脑上用SipSorcery开发小型WPF应用,基于.NET 6和最新版SipSorcery包。用户代理注册成功无报错,但发起呼叫时收到403 Forbidden响应。发现注册和Invite请求使用不同端口,怀疑是问题根源,尝试为SipTransport设置同一端口但未成功,SipSorcery似乎每次都会分配不同端口。
注册请求截图

Invite请求截图

呼叫代码
public async Task MakeCall() { // ... var sipTransport = new SIPTransport(); sipTransport.PreferIPv6NameResolution = preferIPv6; //sipTransport.AddSIPChannel(new List<SIPChannel> { new SIPTCPChannel(IPAddress.Any, 47063) }); sipTransport.CreateChannel(SIPProtocolsEnum.udp,AddressFamily.Unknown,47063); sipTransport.EnableTraceLogs(); SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI); var audioSession = new WindowsAudioEndPoint(new AudioEncoder()); audioSession.RestrictFormats(x => x.Codec == AudioCodecsEnum.PCMA || x.Codec == AudioCodecsEnum.PCMU); var rtpSession = new VoIPMediaSession(audioSession.ToMediaEndPoints()); var offerSDP = rtpSession.CreateOffer(preferIPv6 ? IPAddress.IPv6Any : IPAddress.Any); var uac = new SIPClientUserAgent(sipTransport); // Codes for trying and failing ... etc SIPCallDescriptor callDescriptor = new SIPCallDescriptor( username: DEFAULT_USERNAME, password: DEFAULT_PASSWORD, uri: callUri.ToString(), from: $"sip:{DEFAULT_USERNAME}@{DEFAULT_SERVER}", to: DEFAULT_DESTINATION_SIP_URI, routeSet: null, customHeaders: new List<string> { "Allow:INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH,MESSAGE" ,"User-Agent:SIP.js/0.14.6" }, authUsername: null, callDirection: SIPCallDirection.Out, contentType: SDP.SDP_MIME_CONTENTTYPE, content: offerSDP.ToString(), mangleIPAddress: null); uac.Call(callDescriptor, null); // ... }
注册代码
public void RegisterSipUser() { SIPTransport.PreferIPv6NameResolution = true; SIPTransport.EnableTraceLogs(); Log = AddFileLogger(LogEventLevel.Verbose); SIPURI sIPURI = new SIPURI(DEFAULT_USERNAME, HOST, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp); SIPEndPoint sIPEndPoint = new SIPEndPoint(sIPURI); _userAgent = new SIPRegistrationUserAgent(SIPTransport, sIPEndPoint, sIPURI, DEFAULT_USERNAME, DEFAULT_PASSWORD, "xxx.net", HOST, sIPURI, DEFAULT_EXPIRY,null); _userAgent.UserAgent = "SIP.js/0.14.6"; // Event handlers for the different stages of the registration. _userAgent.RegistrationFailed += (uri, err) => Log.LogError($"{uri}: {err}"); _userAgent.RegistrationTemporaryFailure += (uri, msg) => Log.LogError($"{uri}: {msg}"); _userAgent.RegistrationRemoved += (uri) => Log.LogWarning($"{uri} registration failed."); _userAgent.RegistrationSuccessful += (uri) => Log.LogInformation($"{uri} registration succeeded."); _userAgent.Start(); }
疑问
- 注册与呼叫使用不同端口是否会引发问题?
- 如何为这两个操作设置同一端口?
解答
1. 注册与呼叫使用不同端口是否会引发问题?
是的,这大概率是403 Forbidden的诱因。很多SIP服务器会把"注册请求源端口与后续呼叫请求源端口一致"作为安全校验条件——端口不一致时,服务器会判定呼叫请求并非来自已注册的合法客户端,直接拒绝请求返回403。
2. 如何为这两个操作设置同一端口?
你的代码核心问题是注册和呼叫各自创建了独立的SIPTransport实例,这必然导致系统分配不同端口。解决方法是复用全局唯一的SIPTransport实例:
步骤1:创建全局共享的SIPTransport
在应用初始化阶段创建单例SIPTransport并指定固定端口:
// 全局单例,应用启动时初始化一次 private static SIPTransport _globalSipTransport; public void InitializeSipTransport(bool preferIPv6) { _globalSipTransport = new SIPTransport(); _globalSipTransport.PreferIPv6NameResolution = preferIPv6; // 明确指定UDP端口47063,确保注册和呼叫共用该端口 _globalSipTransport.CreateChannel(SIPProtocolsEnum.udp, AddressFamily.Unknown, 47063); _globalSipTransport.EnableTraceLogs(); }
步骤2:注册和呼叫复用该实例
- 注册代码修改:
public void RegisterSipUser() { // 使用全局实例,不再操作静态属性 _globalSipTransport.EnableTraceLogs(); Log = AddFileLogger(LogEventLevel.Verbose); SIPURI sIPURI = new SIPURI(DEFAULT_USERNAME, HOST, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp); SIPEndPoint sIPEndPoint = new SIPEndPoint(sIPURI); // 传入全局SIPTransport实例 _userAgent = new SIPRegistrationUserAgent(_globalSipTransport, sIPEndPoint, sIPURI, DEFAULT_USERNAME, DEFAULT_PASSWORD, "xxx.net", HOST, sIPURI, DEFAULT_EXPIRY,null); _userAgent.UserAgent = "SIP.js/0.14.6"; // 事件处理代码保持不变 _userAgent.Start(); }
- 呼叫代码修改:
public async Task MakeCall() { // 直接复用全局实例,无需重新创建 var sipTransport = _globalSipTransport; SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI); var audioSession = new WindowsAudioEndPoint(new AudioEncoder()); audioSession.RestrictFormats(x => x.Codec == AudioCodecsEnum.PCMA || x.Codec == AudioCodecsEnum.PCMU); var rtpSession = new VoIPMediaSession(audioSession.ToMediaEndPoints()); var offerSDP = rtpSession.CreateOffer(preferIPv6 ? IPAddress.IPv6Any : IPAddress.Any); var uac = new SIPClientUserAgent(sipTransport); // 呼叫描述符代码保持不变 uac.Call(callDescriptor, null); }
额外注意事项
- 确保全局SIPTransport只初始化一次,避免重复创建导致端口冲突。
- 如果设置固定端口后仍有问题,检查防火墙是否允许该端口的UDP流量,以及SIP服务器是否支持自定义端口的注册/呼叫请求。
内容的提问来源于stack exchange,提问作者nzrytmn
相关产品推荐
相关产品推荐

