c#中读取套接字时算术运算溢出

本文关键字:算术运算 溢出 套接字 读取 | 更新日期: 2023-09-27 18:13:55

所以我决定通过给自己一些有趣的任务来开始学习它。作为一名web开发人员,我想拥有自己的WebSocket服务器。所以我写了它,但它只接受第一个请求。之后是算术运算溢出。
下面是一些代码,让你看看我做错了什么:S我真的没有主意了。

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using WebSocket.Utils;
namespace WebSocket
{
    class SocketReader
    {
        public EndPoint ipAddr { get; set; }
        private Socket userSocket;
        private byte[] buffer;
        private string SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        public SocketReader(Socket socket)
        {
            userSocket = socket;
            ipAddr = socket.RemoteEndPoint;
            Read();
        }
        private void Read()
        {
            //Read packet size
            buffer = new byte[2];
            userSocket.BeginReceive(buffer, 0, 2, SocketFlags.None, ReadCallbackStatic, null);
        }
        private void ReadCallbackStatic(IAsyncResult ar)
        {
            try
            {
                if (userSocket.EndReceive(ar) >= 1)
                {
                    int bufferSize = BitConverter.ToInt16(buffer, 0);
                    buffer = new byte[bufferSize - 2];
                    //Read Packet
                    userSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReadCallback, null);
                }
            }
            catch (Exception se)
            {
                Console.WriteLine("Something blew on ReadCallbackStatic");
                Console.WriteLine(se.Message);
                Console.WriteLine(se.StackTrace);
                Disconnect();
            }
        }
        private void ReadCallback(IAsyncResult ar)
        {
            try
            {
                //Copy the buffer so we can receive the next packet ASAP
                byte[] buff = new byte[buffer.Length];
                Array.Copy(buffer, buff, buffer.Length);
                Read();
                string handshakeStr = System.Text.Encoding.UTF8.GetString(buff);
                string[] list = Regex.Split(handshakeStr, "'r'n");
                //Sec-WebSocket-Key: S5o6fCVLRMJhdXTF3H9w3Q==
                //Sec-WebSocket-Version: 8
                string key = "";
                string clientProtocol = "0";
                foreach (string str in list)
                {
                    if (String.IsNullOrEmpty(str)) { continue; }
                    if (str.Length > 20 && str.Substring(0, 19) == "Sec-WebSocket-Key: ")
                    {
                        key = str.Substring(19);
                        continue;
                    }
                    if (str.Length > 20 && str.Substring(0, 23) == "Sec-WebSocket-Version: ")
                    {
                        clientProtocol = str.Substring(23);
                        continue;
                    }
                }
                if (String.IsNullOrEmpty(key))
                {
                    Disconnect();
                }
                SHA1 shaEnc = new SHA1CryptoServiceProvider();
                byte[] byteString = ASCIIEncoding.ASCII.GetBytes(key + SOCKET_GUID);
                byte[] hash = shaEnc.ComputeHash(byteString, 0, byteString.Length);
                string acceptKey = Convert.ToBase64String(hash);
                List<string> headers = new List<string>();
                headers.Add("HTTP/1.1 101 Switching Protocols");
                headers.Add("Upgrade: websocket");
                headers.Add("Connection: Upgrade");
                headers.Add("Sec-WebSocket-Accept: " + acceptKey);
                foreach (string header in headers)
                {
                    SendString(header + "'r'n");
                }
                Console.WriteLine(acceptKey);
                SendString("'r'n");
            }
            catch (SocketException se)
            {
                Console.WriteLine("Something blew on ReadCallback");
                Console.WriteLine(se.Message);
                Disconnect();
            }
        }
        private void SendString(string str)
        {
            userSocket.Send(Encoding.UTF8.GetBytes(str));
        }
        private void Disconnect()
        {
            userSocket.Disconnect(false);
            Console.WriteLine("Client with ip {0} Disconnected", ipAddr);
        }
    }
}

这是我的类的缩短版本,但问题是困扰我出现在"ReadCallbackStatic"在这一行:

buffer = new byte[bufferSize - 2];
我真的不知道我做错了什么。
问题是……实际上握手是正确的但是当我从客户端向服务器发送一些信息时这个异常被抛出

我做了一些调试,好像缓冲区变量变成了负数o

c#中读取套接字时算术运算溢出

我的猜测是,当MSB设置时,您会爆炸,即可能客户端正在发送一个数字>= 32768和<65536,它(通过您的ToInt16)正在变成一个大的负16位数(或者,或者,抛出算术溢出问题)。我会尝试使用ToUInt16代替。

老实说,这里真的不需要BitConverter;根据端序的不同,这是:

int bufferSize = (buffer[0] << 8) | buffer[1];

int bufferSize = buffer[0] | (buffer[1] << 8);

我认为问题可能是在缓冲区包含零数的情况下,所以:

  int bufferSize = BitConverter.ToInt16(buffer, 0); // 0
  buffer = new byte[bufferSize - 2];  // 0 - 2 == -2

在执行new byte[-2]

时导致溢出异常

我不知道你的代码背后的逻辑,但我相信你应该分配一个新的缓冲区考虑buffer.Length