You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 14:36:20