基于TCP/UDP协议的C#网络电台开发问题求助及调试
网络电台开发问题解决方案
背景
尝试基于TCP/UDP协议开发网络电台,将域名21303.live.streamtheworld.com解析为IP149.6.43.235后,编写了多版C#代码,但分别遇到无输出、播放失败、API调用错误等问题,以下是针对性解决方案:
1. 初始Socket连接代码:无输出无报错
问题原因:
仅完成连接和发送"testing"字符串,但未接收服务器响应,也没有发送符合流媒体服务器要求的标准化请求(服务器会忽略无效请求,无数据返回)。
修正方案:
发送标准HTTPS GET请求获取流媒体流,添加响应接收逻辑,同时处理SSL加密:
using System; using System.Net; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; namespace NetworkProgramming { public class IPEndPointSample { public static void Main() { IPAddress host = IPAddress.Parse("149.6.43.235"); IPEndPoint hostep = new IPEndPoint(host, 443); using Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { sock.Connect(hostep); // 用SslStream处理HTTPS加密 using var sslStream = new System.Net.Security.SslStream(sock.GetStream(), false, ValidateServerCert); sslStream.AuthenticateAsClient("21303.live.streamtheworld.com"); // 发送标准HTTP GET请求 string request = "GET /METRO_FM_SC HTTP/1.1\r\nHost: 21303.live.streamtheworld.com\r\nConnection: keep-alive\r\n\r\n"; byte[] requestBytes = Encoding.ASCII.GetBytes(request); sslStream.Write(requestBytes, 0, requestBytes.Length); // 接收服务器响应 byte[] buffer = new byte[4096]; int bytesRead = sslStream.Read(buffer, 0, buffer.Length); Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytesRead)); } catch (Exception e) { Console.WriteLine("连接或通信出错:"); Console.WriteLine(e.ToString()); } } // 测试环境跳过证书验证 private static bool ValidateServerCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors) { return true; } } }
2. 更新后的TcpClient代码:无有效响应
问题原因:
发送的请求格式不符合HTTP规范,开头的\n导致服务器无法解析请求,没有返回有效数据。
修正方案:
发送标准HTTPS请求,用SslStream处理加密通信:
using System; using System.Net; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; public class Program { public static void Main() { using var client = new TcpClient(); var hostname = "21303.live.streamtheworld.com"; client.Connect(hostname, 443); using var sslStream = new System.Net.Security.SslStream(client.GetStream(), false, ValidateServerCert); try { sslStream.AuthenticateAsClient(hostname); } catch (AuthenticationException e) { Console.WriteLine("SSL认证失败:"); Console.WriteLine(e.ToString()); return; } sslStream.ReadTimeout = 5000; // 标准HTTP GET请求 string request = "GET /METRO_FM_SC HTTP/1.1\r\nHost: 21303.live.streamtheworld.com\r\nConnection: close\r\n\r\n"; byte[] requestBytes = Encoding.UTF8.GetBytes(request); sslStream.Write(requestBytes, 0, requestBytes.Length); // 读取完整响应 byte[] buffer = new byte[4096]; int bytesRead; StringBuilder response = new StringBuilder(); while ((bytesRead = sslStream.Read(buffer, 0, buffer.Length)) > 0) { response.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); } Console.WriteLine(response.ToString()); } private static bool ValidateServerCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors) { return true; } }
3. 结合NAudio的WinForm代码:播放错误
问题原因:
- 传入的流媒体地址不是完整URL(缺少协议和路径);
- 使用
MemoryStream不适合实时流媒体的持续播放,Mp3FileReader无法处理实时写入的流; - 线程逻辑混乱,UI线程被阻塞,缓冲逻辑不合理。
修正方案:
使用BufferedWaveProvider实时缓冲音频流,播放逻辑放在后台线程:
using NAudio.Wave; using System.Net.Http; using System.Threading.Tasks; namespace tcpnadudio { public partial class Form1 : Form { private WaveOutEvent _waveOut; private BufferedWaveProvider _bufferedWaveProvider; public Form1() { InitializeComponent(); } private async void Form1_Load(object sender, EventArgs e) { await PlayMp3StreamAsync("https://21303.live.streamtheworld.com/METRO_FM_SC"); } private async Task PlayMp3StreamAsync(string url) { _waveOut = new WaveOutEvent(); _bufferedWaveProvider = new BufferedWaveProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)); _bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(10); // 设置10秒缓冲 _waveOut.Init(_bufferedWaveProvider); _waveOut.Play(); using var httpClient = new HttpClient(); using var stream = await httpClient.GetStreamAsync(url); using var mp3Reader = new Mp3FileReader(stream); using var pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader); byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = pcmStream.Read(buffer, 0, buffer.Length)) > 0) { _bufferedWaveProvider.AddSamples(buffer, 0, bytesRead); // 缓冲不足时等待 while (_bufferedWaveProvider.BufferedDuration < TimeSpan.FromSeconds(1)) { await Task.Delay(100); } } _waveOut.Stop(); _waveOut.Dispose(); } protected override void OnFormClosing(FormClosingEventArgs e) { _waveOut?.Stop(); _waveOut?.Dispose(); base.OnFormClosing(e); } } }
4. 集成Shazam API的代码:内部服务器错误
问题原因:
- Shazam API请求URL格式错误(
key=-------=en-US参数无效); - 调用的
get-details接口需要有效歌曲key,无法直接识别音频; - HttpClient未复用,API调用放在播放循环中频繁执行,逻辑混乱;
- SignalR的
_hubContext未正确初始化,且与音频识别逻辑无关。
修正方案:
使用Shazam音频识别接口,定时抽取音频片段进行识别,整理逻辑:
using NAudio.Wave; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; namespace RadioStream { public partial class Form1 : Form { private WaveOutEvent _waveOut; private BufferedWaveProvider _bufferedWaveProvider; private readonly HttpClient _httpClient; private readonly string _shazamApiKey = "你的RapidAPI密钥"; public Form1() { InitializeComponent(); _httpClient = new HttpClient(); _httpClient.DefaultRequestHeaders.Add("X-RapidAPI-Key", _shazamApiKey); _httpClient.DefaultRequestHeaders.Add("X-RapidAPI-Host", "shazam.p.rapidapi.com"); } private async void Form1_Load(object sender, EventArgs e) { await PlayAndRecognizeAsync("https://21303.live.streamtheworld.com/METRO_FM_SC"); } private async Task PlayAndRecognizeAsync(string url) { _waveOut = new WaveOutEvent(); _bufferedWaveProvider = new BufferedWaveProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)); _waveOut.Init(_bufferedWaveProvider); _waveOut.Play(); using var stream = await _httpClient.GetStreamAsync(url); using var mp3Reader = new Mp3FileReader(stream); using var pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader); byte[] buffer = new byte[8192]; int bytesRead; int recognizeCounter = 0; while ((bytesRead = pcmStream.Read(buffer, 0, buffer.Length)) > 0) { _bufferedWaveProvider.AddSamples(buffer, 0, bytesRead); // 每10秒识别一次 recognizeCounter += bytesRead; if (recognizeCounter > 44100 * 2 * 10) // 10秒PCM数据(44.1kHz双声道) { await RecognizeAudio(buffer); recognizeCounter = 0; } while (_bufferedWaveProvider.BufferedDuration < TimeSpan.FromSeconds(1)) { await Task.Delay(100); } } _waveOut.Stop(); } private async Task RecognizeAudio(byte[] audioData) { try { var request = new HttpRequestMessage(HttpMethod.Post, "https://shazam.p.rapidapi.com/shazam/song-recognition"); request.Content = new ByteArrayContent(audioData); request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); request.Content.Headers.Add("sampleRate", "44100"); using var response = await _httpClient.SendAsync(request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Console.WriteLine("Shazam识别结果:" + result); } catch (HttpRequestException e) { Console.WriteLine("Shazam API调用失败:" + e.Message); } } protected override void OnFormClosing(FormClosingEventArgs e) { _waveOut?.Stop(); _waveOut?.Dispose(); _httpClient.Dispose(); base.OnFormClosing(e); } } }
内容的提问来源于stack exchange,提问作者userx
相关产品推荐
相关产品推荐

