Socket的ReceiveAsync和SendAsync变成Task<int>

本文介绍了一种针对Socket的SendAsync和ReceiveAsync方法的封装方案,通过创建一系列实用的异步函数来简化网络编程任务,并确保与现代异步编程模式兼容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在无阻塞环境,Socket的SendAsync和ReceiveAsync显得特别另类。他们返回的不是Task而是bool 值。为了与开发环境兼容【其实就是为了使用ContinueWith】,需要将他们封装,返回为Task<int>.

以下为转换函数:

public class SocketTokenInfo
    {
        public static int SocketMaxWaitTime = 1000 * 60;//Socket一次发送,接收最大的等待时间。单位:毫秒

        ByteBuffer Buffer;

        System.Net.Sockets.Socket Socket;
        System.Net.Sockets.SocketAsyncEventArgs Event;
        System.Threading.CancellationTokenSource Cancel;
        Exception Error;

        Task<int> returnTask;
        int returnValue = -1;//GetData时,是接收到的数据长度. GetHttpHead时,是httpheader的结束位置.
        int ReceivedBytes()
        {
            if (Error != null)
                throw Error;
            return returnValue;
        }

        void CheckCall()
        {
            if (Buffer != null)
                throw new Exception("ReCall Socket Function when Task not end.");
        }

        void EndTaskCall()
        {
            try
            {
                //Cancel.Dispose();
                Event.Dispose();
            }
            catch { }

            Task tmp = returnTask;
            Event.UserToken = null;
            Event = null;
            //Cancel = null;
            returnTask = null;
            HelperExtend.socketToken.Ended(this);

            tmp.Start();
        }


        Task<int> CreatTask()
        {
            if (Cancel == null)
            {
                Cancel = new System.Threading.CancellationTokenSource();
            }
            returnValue = 0;
            Error = null;
            Cancel.CancelAfter(SocketMaxWaitTime);
            returnTask = new Task<int>(ReceivedBytes, Cancel.Token);
            return returnTask;
        }

        #region 发送数据

        public Task<int> SendData(System.Net.Sockets.Socket s, ByteBuffer buf, System.Net.Sockets.SocketAsyncEventArgs e = null)
        {
            CheckCall();

            if (e == null)
                e = new System.Net.Sockets.SocketAsyncEventArgs();
            Event = e;
            e.UserToken = this;

            this.Buffer = buf;
            Buffer.SocketSendEvent(Event);
            this.Socket = s;

            Event.Completed += CheckSend;
            if (!s.SendAsync(Event))
            {
                CheckSend(s, Event);
            }

            return CreatTask();
        }

        void CheckSend(object sender, System.Net.Sockets.SocketAsyncEventArgs Event)
        {
            Event.Completed -= CheckSend;
            returnValue = Event.BytesTransferred;
            this.Buffer.Readed(returnValue);
            EndTaskCall();
        }

        #endregion

        #region HttpHead
        public Task<int> GetHttpHead(System.Net.Sockets.Socket s, ByteBuffer buf, System.Net.Sockets.SocketAsyncEventArgs e=null)
        {
            CheckCall();

            if (e == null)
                e = new System.Net.Sockets.SocketAsyncEventArgs();
            Event = e;
            Event.UserToken = this;

            this.Buffer = buf;
            this.Buffer.SocketReceiveEvent(Event);
            Socket = s;
            

            Event.Completed += CheckHttp;
            if (!s.ReceiveAsync(Event))
            {
                CheckHttp(s, Event);
            }

            return CreatTask();
        }

        void CheckHttp(object sender, System.Net.Sockets.SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred <= 0)
            {//连接已断开.
                Event.Completed -= CheckHttp;
                this.Error = new Exception("Socket is disconnted before headers are received");

                this.EndTaskCall();
                return;
            }
            
            int oldLen = this.Buffer.Count;//上次检查结束位置.
            this.Buffer.Writed(e.BytesTransferred);

            int rtVlue = this.Buffer.LineDoubleCheckASC2(oldLen);//检查\r\n\r\n
            if (rtVlue < 0)
            {//未完成,继续接收数据.
                if (!this.Socket.ReceiveAsync(Event))
                {
                    CheckHttp(this.Socket, Event);
                }
            }
            else
            {//完成httpHeader的接收
                returnValue = rtVlue;
                EndTaskCall();
            }
        }
        #endregion

        #region GetOnce
        //执行一次socket取数据操作.无论是否成功.
        public Task<int> GetOnce(System.Net.Sockets.Socket s,ByteBuffer buf, System.Net.Sockets.SocketAsyncEventArgs e=null)
        {
            CheckCall();

            if (e == null)
                e = new System.Net.Sockets.SocketAsyncEventArgs();
            Event = e;
            e.UserToken = this;

            this.Buffer = buf;
            this.Buffer.SocketReceiveEvent(Event);
            Socket = s;

            Event.Completed += CheckReceiveRst;
            if (!s.ReceiveAsync(Event))
            {
                CheckReceiveRst(s, Event);
            }

            return CreatTask();
        }

        void CheckReceiveRst(object sender, System.Net.Sockets.SocketAsyncEventArgs e)
        {
            Event.Completed -= CheckReceiveRst;
            returnValue = Event.BytesTransferred;
            this.Buffer.Writed(Event.BytesTransferred);

            EndTaskCall();
        }
        #endregion


        #region GetFixLen
        //执行一次socket取数据操作.无论是否成功.
        public Task<int> GetFixLength(System.Net.Sockets.Socket s,int ask,ByteBuffer buf, System.Net.Sockets.SocketAsyncEventArgs e = null)
        {
            CheckCall();

            if (e == null)
                e = new System.Net.Sockets.SocketAsyncEventArgs();
            Event = e;
            e.UserToken = this;

            this.Buffer = buf;
            this.Buffer.SocketReceiveEvent(Event);
            Socket = s;

            returnValue = ask;

            Event.Completed += CheckAskLen;
            if (!s.ReceiveAsync(Event))
            {
                CheckAskLen(s, Event);
            }

            return CreatTask();
        }

        void CheckAskLen(object sender, System.Net.Sockets.SocketAsyncEventArgs Event)
        {
            if(Event.BytesTransferred <= 0)
            {
                Event.Completed -= CheckAskLen;
                this.Error = new Exception("Socket Closed Before Data All");
                EndTaskCall();
                return;
            }

            this.Buffer.Writed(Event.BytesTransferred);
            if(this.Buffer.Count >= returnValue)
            {
                Event.Completed -= CheckAskLen;
                EndTaskCall();
                return;
            }

            if (!this.Socket.ReceiveAsync(Event))
            {
                CheckAskLen(this.Socket, Event);
            }
        }
        #endregion

        #region All
        //接收数据,等待对方断开连接后返回.
        public Task<int> GetAllAndClose(System.Net.Sockets.Socket s, System.Net.Sockets.SocketAsyncEventArgs e, ByteBuffer buf)
        {

            CheckCall();

            if (e == null)
                e = new System.Net.Sockets.SocketAsyncEventArgs();
            Event = e;
            Event.UserToken = this;

            this.Buffer = buf;
            this.Buffer.SocketReceiveEvent(Event);
            Socket = s;


            Event.Completed += CheckAll;
            if (!s.ReceiveAsync(Event))
            {
                CheckAll(s, Event);
            }

            return CreatTask();
        }

        void CheckAll(object sender, System.Net.Sockets.SocketAsyncEventArgs e)
        {
            if (Event.BytesTransferred <= 0)
            {
                Event.Completed -= CheckAll;
                this.Socket.Shutdown(System.Net.Sockets.SocketShutdown.Both);
                this.Socket.Dispose();
                return;
            }
            else
            {
                this.Buffer.Writed(Event.BytesTransferred);
                if (!this.Socket.ReceiveAsync(Event))
                {
                    CheckAll(Socket, Event);
                }
            }
        }
        #endregion
        
        public void DoCancel()
        {
            Cancel.Cancel();
        }
    }

ByteBuffer 是一个缓冲区管理函数.

 

 

 

 

 

 

 

 

 

 

using System.Net.Sockets; using System.Net; using System.Text; using System; using System.Diagnostics; namespace 上位机 { public partial class statetext1 : Form { public statetext1() { InitializeComponent(); // 正确地初始化 Timer runtimeTimer.Interval = 1000; runtimeTimer.Tick += (s, e) => yunx(); } void ipaddr(string data) { if (this.iptext.InvokeRequired) { this.iptext.Invoke(new Action<string>(ipaddr), data); } else { this.iptext.Text = data; } } void SL(string data) { if (this.SY_TEXT.InvokeRequired) { this.SY_TEXT.Invoke(new Action<string>(SL), data); } else { this.SY_TEXT.Text = data; } } void AX(string data) { if (this.AX_TEXT.InvokeRequired) { this.AX_TEXT.Invoke(new Action<string>(AX), data); } else { this.AX_TEXT.Text = data; } } void AY(string data) { if (this.AY_TEXT.InvokeRequired) { this.AY_TEXT.Invoke(new Action<string>(AY), data); } else { this.AY_TEXT.Text = data; } } void AZ(string data) { if (this.AZ_TEXT.InvokeRequired) { this.AZ_TEXT.Invoke(new Action<string>(AZ), data); } else { this.AZ_TEXT.Text = data; } } void GX(string data) { if (this.GX_TEXT.InvokeRequired) { this.GX_TEXT.Invoke(new Action<string>(GX), data); } else { this.GX_TEXT.Text = data; } } void GY(string data) { if (this.GY_TEXT.InvokeRequired) { this.GY_TEXT.Invoke(new Action<string>(GY), data); } else { this.GY_TEXT.Text = data; } } void GZ(string data) { if (this.GZ_TEXT.InvokeRequired) { this.GZ_TEXT.Invoke(new Action<string>(GZ), data); } else { this.GZ_TEXT.Text = data; } } void TEMP(string data) { if (this.TEMP_TEXT.InvokeRequired) { this.TEMP_TEXT.Invoke(new Action<string>(TEMP), data); } else { this.TEMP_TEXT.Text = data; } } void HUM(string data) { if (this.HUM_TEXT.InvokeRequired) { this.HUM_TEXT.Invoke(new Action<string>(HUM), data); } else { this.HUM_TEXT.Text = data; } } void LIGHT(string data) { if (this.LIGHT_TEXT.InvokeRequired) { this.LIGHT_TEXT.Invoke(new Action<string>(LIGHT), data); } else { this.LIGHT_TEXT.Text = data; } } void MQA(string data) { if (this.MQA_TEXT.InvokeRequired) { this.MQA_TEXT.Invoke(new Action<string>(MQA), data); } else { this.MQA_TEXT.Text = data; } } void MQB(string data) { if (this.MQB_TEXT.InvokeRequired) { this.MQB_TEXT.Invoke(new Action<string>(MQB), data); } else { this.MQB_TEXT.Text = data; } } void FLASH(string data) { if (this.FLASH_TEXT.InvokeRequired) { this.FLASH_TEXT.Invoke(new Action<string>(FLASH), data); } else { this.FLASH_TEXT.Text = data; } } void TIME(string data) { if (this.tim_text.InvokeRequired) { this.tim_text.Invoke(new Action<string>(TIME), data); } else { this.tim_text.Text = data; } } void Msg(string msg) { if (this.Msg_Text.InvokeRequired) { this.Msg_Text.Invoke(new Action<string>(Msg), msg); } else { this.Msg_Text.Text = this.Msg_Text.Text + DateTime.Now.ToString() + " --->" + msg + "\r\n"; this.Msg_Text.SelectionStart = this.Msg_Text.TextLength - 1; this.Msg_Text.ScrollToCaret(); } } int GetIntValue(string data, string startKey, string endKey) { int start = data.IndexOf(startKey); int end = data.IndexOf(endKey); if (start == -1 || end == -1 || end <= start) return 0; start += startKey.Length; string numStr = data.Substring(start, end - start); if (int.TryParse(numStr, out int result)) { return result; } return 0; } private System.Windows.Forms.Timer runtimeTimer = new System.Windows.Forms.Timer(); Stopwatch sw = Stopwatch.StartNew(); void date_dispose(string recvDate) { if (recvDate.StartsWith("ZETA")) { try { // 用正则表达式提取字段 int ax = GetIntValue(recvDate, "X", "AY"); int ay = GetIntValue(recvDate, "AY", "AZ"); int az = GetIntValue(recvDate, "AZ", "GX"); int gx = GetIntValue(recvDate, "GX", "GY"); int gy = GetIntValue(recvDate, "GY", "GZ"); int gz = GetIntValue(recvDate, "GZ", "MQA"); int mqa = GetIntValue(recvDate, "MQA", "MQB"); int mqb = GetIntValue(recvDate, "MQB", "TEMP"); int temp = GetIntValue(recvDate, "TEMP", "HUM"); int hum = GetIntValue(recvDate, "HUM", "LIGHT"); int light = GetIntValue(recvDate, "LIGHT", "FLASH"); string flashStr = recvDate.Substring(recvDate.IndexOf("FLASH") + 5); List<byte> flashData = new List<byte>(); if (flashStr.Length > 25) { flashStr = flashStr.Substring(0, 25); } for (int i = 0; i + 2 <= flashStr.Length && flashData.Count < 8; i += 2) { string byteStr = flashStr.Substring(i, 2); byte val = Convert.ToByte(byteStr, 16); flashData.Add(val); } this.AX(ax.ToString()); this.AX(ax.ToString()); this.AY(ay.ToString()); this.AZ(az.ToString()); this.GX(gx.ToString()); this.GY(gy.ToString()); this.GZ(gz.ToString()); this.TEMP(temp.ToString()); this.HUM(hum.ToString()); this.LIGHT(light.ToString()); this.MQA(mqa.ToString()); this.MQB(mqb.ToString()); this.FLASH(flashStr); } catch (Exception ex) { // 捕获解析异常 Console.WriteLine("数据解析异常:" + ex.Message); } } } // 获取本地IP地址的方法 private string GetLocalIPAddress() { var host = Dns.GetHostEntry(Dns.GetHostName()); foreach (var ip in host.AddressList) { // 过滤出IPv4地址 if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { return ip.ToString(); } } return string.Empty; // 没有找到IPv4地址时返回空字符串 } //创建SOCKET private TcpListener server; private CancellationTokenSource serverTokenSource; // 修改 StartServer 方法以支持多客户端连接 string dqip; string dqdk; string sendCMD; UdpClient udpServer; CancellationTokenSource udpTokenSource; private bool isConnected = false; private void StartUdpServer() { int portNumber = int.Parse(port.Text); udpServer = new UdpClient(portNumber); udpTokenSource = new CancellationTokenSource(); Msg("UDP 服务已启动,等待数据中..."); string localIP = GetLocalIPAddress(); if (!string.IsNullOrEmpty(localIP)) { this.ipaddr(localIP); } long totalBytesReceived = 0; object bytesLock = new object(); // 统计速率的定时任务 Task.Run(async () => { while (!udpTokenSource.Token.IsCancellationRequested) { long bytesPerSecond = 0; lock (bytesLock) { bytesPerSecond = totalBytesReceived; totalBytesReceived = 0; } string speedText; if (bytesPerSecond < 1024) speedText = $"{bytesPerSecond} B/s"; else speedText = $"{(bytesPerSecond / 1024.0):F2} KB/s"; this.SL(speedText); await Task.Delay(1000); } }, udpTokenSource.Token); // 接收数据任务 Task.Run(async () => { try { while (!udpTokenSource.Token.IsCancellationRequested) { UdpReceiveResult result = await udpServer.ReceiveAsync(); string requestData = Encoding.ASCII.GetString(result.Buffer); // 累计接收字节数 lock (bytesLock) { totalBytesReceived += result.Buffer.Length; } if (!string.IsNullOrEmpty(requestData.Trim())) { Msg($"收到来自 {result.RemoteEndPoint} 的数据: {requestData}"); date_dispose(requestData); if (!string.IsNullOrEmpty(sendCMD)) { byte[] responseBuffer = Encoding.ASCII.GetBytes(sendCMD); await udpServer.SendAsync(responseBuffer, responseBuffer.Length, result.RemoteEndPoint); sendCMD = string.Empty; } } } } catch (ObjectDisposedException) { Msg("UDP 服务已关闭。"); } catch (Exception ex) { Msg("UDP 接收时异常:" + ex.Message); } }, udpTokenSource.Token); } void yunx() { TimeSpan ts = sw.Elapsed; string timeStr = ts.ToString(@"hh\:mm\:ss"); // 格式:00:01:23 this.TIME(timeStr); } private void Disconnect() { isConnected = false; udpTokenSource?.Cancel(); udpTokenSource?.Dispose(); udpServer?.Close(); // 注意 UDP 使用 Close() udpServer?.Dispose(); } private void button1_Click(object sender, EventArgs e) { if (isConnected) { connect.Text = "开启"; Disconnect(); sw.Stop(); // 停止计时 runtimeTimer.Stop(); // 停止定时器 isConnected = false; } else { connect.Text = "关闭"; sendCMD = string.Empty; sw.Reset(); // 清零(可选) sw.Start(); // 开始计时 runtimeTimer.Start(); // 开始定时器 StartUdpServer(); isConnected = true; } } private void label13_Click(object sender, EventArgs e) { } private void label21_Click(object sender, EventArgs e) { } private void label22_Click(object sender, EventArgs e) { } private void MQB_TEXT_Click(object sender, EventArgs e) { } private void tim_text_Click(object sender, EventArgs e) { } } }
最新发布
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值