为什么Socket服务端会出现监听异常?

xudisou6088 2017-07-11 11:37:36
是这样的,小弟用SocketAsyncEventArgs类写了个web服务器,用的AcceptAsync、ReceiveAsync、SendAsync实现的
代码是没有报错的,所以并不知道是监听异常还是accept异常或者是其他的

问题发生在:当大量网络爬虫访问一段时间后,服务端就连不上了,访问127.0.0.1也不行,观察发现,这时服务端没有再向外发送流量 ,用Tcp-z查看tcp连接数在快速下降,同时查看任务管理器却发现该进程的线程数却在快速上涨,最后到tcp连接数掉到差不多了,服务端的线程数也降下来了,这时服务端的访问才恢复正常。

感觉应该是爬虫客户端在请求完成后短时间内关闭大量连接时造成的,但这是为什么?而且这时服务端进程的线程数在快速上涨,但我并没有去开任何线程啊,在连接断开后我也执行了Shutdown和Close

不明白,该如何解决,新手求教!谢谢
...全文
545 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
xudisou6088 2017-07-20
  • 打赏
  • 举报
回复
有大神吗 顶一下
  • 打赏
  • 举报
回复
“代码是没有报错的”这个说法通常代表着背后的工程问题。好的程序通常很少有 try...catch,而初学者才会以为 try..catch 越多越好。
  • 打赏
  • 举报
回复
除了代码,其实更重要的是工程问题。在 debug 阶段,大量测试阶段,通常要移除掉绝大多数的 try...catch。否则你丧失了测试和调试能力,自己不进行高强度的测试(测试阶段不是自欺欺人地try...catch,相反是让异常尽早调出来),只会求人。
  • 打赏
  • 举报
回复
什么叫做“代码是没有报错的”呢?解释一下。通常这个说法有严重的背景问题。 写日志会严重占用CPU资源所以要尽量考虑到日志的代价问题。且不要阻塞I/O和业务线程。接收数据要支持分包和拆包的结果,以免产生大量业务处理bug。接收到数据之后应该异步处理,不要阻塞I/O线程,不要在你处理完业务之后才来开始下一个 Receive。逻辑要简单直接,即使是 pool 也不需要初始化一大堆东西(你是有的有pool,有的则根本没有pool)。
xudisou6088 2017-07-18
  • 打赏
  • 举报
回复
有大神吗 顶一下
xdashewan 2017-07-12
  • 打赏
  • 举报
回复
代码没看出明显问题,此帖子说能支持65535的链接数,你可以下载demo测试下,如果确实可以,他blog里有代码分析,你可以和你自己的比较下看看问题在哪里
  • 打赏
  • 举报
回复
应该是你的tcp连接被占光了,贴下你的代码么,你的端口是指定的还是怎么写的
xudisou6088 2017-07-11
  • 打赏
  • 举报
回复
自己顶一下
xdashewan 2017-07-11
  • 打赏
  • 举报
回复
引用 8 楼 xdashewan 的回复:
你socket都close了都不用new一个新的就能用?
看错了,让我再看看
xdashewan 2017-07-11
  • 打赏
  • 举报
回复
你socket都close了都不用new一个新的就能用?
xudisou6088 2017-07-11
  • 打赏
  • 举报
回复
客户端connect超时,错误10060
xudisou6088 2017-07-11
  • 打赏
  • 举报
回复
引用 5 楼 starfd 的回复:
你用的是iis吗?是不是你iis连接数达到了最大?
是这样的,小弟用SocketAsyncEventArgs类写了个web服务器,用的AcceptAsync、ReceiveAsync、SendAsync实现的 代码是没有报错的,所以并不知道是监听异常还是accept异常或者是其他的
  • 打赏
  • 举报
回复
你用的是iis吗?是不是你iis连接数达到了最大?
xudisou6088 2017-07-11
  • 打赏
  • 举报
回复
引用 3 楼 starfd 的回复:
http://www.cnblogs.com/lancidie/archive/2011/12/15/2289337.html 端口没达到上限,应该是线程数达到上限了
但是我进程的线程数最高的时候才100多,远远没达到文章中说的那个数吧
  • 打赏
  • 举报
回复
http://www.cnblogs.com/lancidie/archive/2011/12/15/2289337.html 端口没达到上限,应该是线程数达到上限了
xudisou6088 2017-07-11
  • 打赏
  • 举报
回复
引用 1 楼 starfd 的回复:
应该是你的tcp连接被占光了,贴下你的代码么,你的端口是指定的还是怎么写的
连接应该不会占光吧,当时才2000不到的连接数,侦听的80端口 代码:

  private static int _maxConnectCount = 20000;
        private static Socket _socketListen;
        private const int _bufferSize = 4096;
        private static double _nowUploadBit, _nowDownloadBit;
        private static Semaphore _sea;
        private static UserTokenPool _userTokenPool;
        private static void Init()
        {
            _sea = new Semaphore(_maxConnectCount, _maxConnectCount);
            _userTokenPool = new UserTokenPool(_maxConnectCount);
            UserToken userToken;
            for (int i = 0; i < _maxConnectCount; i++)
            {
                userToken = new UserToken(_bufferSize);
                userToken.ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceiveCompleted);
                _userTokenPool.Enqueue(userToken);
            }
        }
        //启动侦听
        public static bool Start()
        {
            try
            {
                Init();
                _socketListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 80);
                _socketListen.Bind(endpoint);
                _socketListen.Listen(Int32.MaxValue);
                _userTokenPool.StartCheckTimeOut(CheckTimeOutSec);
                StartAccept(null);
                return true;
            }
            catch { }
            return false;
        }
        //接收连接
        private static void StartAccept(SocketAsyncEventArgs async)
        {
            try
            {
                if (async == null)
                {
                    async = new SocketAsyncEventArgs();
                    async.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
                }
                else
                {
                    async.AcceptSocket = null;
                }
                //这里设的并发2万,达到2万才会阻塞
                _sea.WaitOne();
                if (!_socketListen.AcceptAsync(async))
                    ProcessAccept(async);
            }
            catch (Exception ex)
            {
                WriteSocketErr("StartAccept:" + ex.Message + ",行号" + ex.StackTrace);
            }
        }
        private static void OnAcceptCompleted(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }
        private static void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
        {
            ProcessReceive(e);
        }
        private static void OnSendCompleted(object sender, SocketAsyncEventArgs e)
        {
            if (e == null)
                return;
            UserToken userToken = e.UserToken as UserToken;
            if (!userToken.IsKeepAlive)
                CloseClientSocket(userToken);
            e.BufferList.Clear();
            e.BufferList = null;
            e.Completed -= new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
            e.Dispose();
            e = null;
        }
        private static void ProcessAccept(SocketAsyncEventArgs e)
        {
            try
            {
                SocketError err = e.SocketError;
                Socket sock = e.AcceptSocket;
                e.AcceptSocket = null;
                StartAccept(e);
                if (err != SocketError.Success)
                    return;
                UserToken userToken = _userTokenPool.Dequeue();
                userToken.Socket = sock;
                string ip = sock.RemoteEndPoint.ToString();
                ip = ip.Remove(ip.IndexOf(":"));
                userToken.IP = ip;
                if (sock.Connected)
                {
                    if (!sock.ReceiveAsync(userToken.ReceiveEventArgs))
                        ProcessReceive(userToken.ReceiveEventArgs);
                }
                else
                    CloseClientSocket(userToken);
            }
            catch (SocketException ex)
            {
                WriteSocketErr("ProcessAccept:" + ex.Message + "\r\n行号" + ex.StackTrace);
            }
        }
        private static void ProcessReceive(SocketAsyncEventArgs e)
        {
            try
            {
                UserToken userToken = e.UserToken as UserToken;
                if (userToken.ReceiveEventArgs.BytesTransferred > 0 && userToken.ReceiveEventArgs.SocketError == SocketError.Success)
                {
                    _nowDownloadBit += userToken.ReceiveEventArgs.BytesTransferred;
                    string header = Encoding.Default.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                   //处理http请求
                    ProcessHttp(userToken, header);
                    if (userToken.Socket != null && userToken.IsKeepAlive && !userToken.Socket.ReceiveAsync(userToken.ReceiveEventArgs))
                        ProcessReceive(userToken.ReceiveEventArgs);
                }
                else
                    CloseClientSocket(userToken);
            }
            catch (Exception ex)
            {
                WriteSocketErr("ProcessReceive:" + ex.Message + "\r\n行号" + ex.StackTrace);
            }
        }
        //处理http请求
        private static void ProcessHttp(userToken, header)
        {
            //
            //处理数据......
            //
            //处理完后发送给客户端
            SendAsync(userToken, buffers);
        }
        private static void SendAsync(UserToken userToken, params byte[][] buffers)
        {
            SocketAsyncEventArgs async = new SocketAsyncEventArgs();
            try
            {
                List<ArraySegment<byte>> list = new List<ArraySegment<byte>>(buffers.Length);
                ArraySegment<byte> ary;
                foreach (var item in buffers)
                {
                    ary = new ArraySegment<byte>(item);
                    list.Add(ary);
                    _nowUploadBit += item.Length;
                }
                async.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
                async.RemoteEndPoint = userToken.Socket.RemoteEndPoint;
                async.BufferList = list;
                async.UserToken = userToken;
                if (!userToken.Socket.SendAsync(async))
                    OnSendCompleted(null, async);
            }
            catch (Exception ex)
            {
                WriteSocketErr("SendAsync:" + ex.Message + "行号:" + ex.StackTrace);
                CloseClientSocket(userToken);
                OnSendCompleted(null, async);
            }
        }
        //关闭连接
        public static void CloseClientSocket(UserToken userToken)
        {
            if (userToken.Socket == null)
                return;
            try
            {
                userToken.Socket.Shutdown(SocketShutdown.Both);
            }
            catch (SocketException ex)
            {
                WriteSocketErr("Shutdown:" + ex.Message);
            }
            try
            {
                userToken.Socket.Close();
            }
            catch (SocketException ex)
            {
                WriteSocketErr("Close:" + ex.Message);
            }
            userToken.Socket = null;
            _userTokenPool.Enqueue(userToken);
            _sea.Release();
        }
        //写入错误文件
        private static void WriteSocketErr(string errMsg)
        {
            lock (locker)
            {
                File.AppendAllText(errFilePath, string.Format("{0} {1}{2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    errMsg, Environment.NewLine), Encoding.UTF8);
            }
        }

111,093

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧