搞清楚TCP/IP的原理先,谁告诉你的一个连接就要开一个线程???

解决方案 »

  1.   


    服务器端 一个监听SOCKET是公用的。
    但维护着与某个终端保持通信的连接SOCKET是每次监听到客户端的请求之后生成的啊? 
    看教程上是这样说的。这样岂不是500个人连接,服务器端就得有500个与客户端通信的SOCKET对象?   
    每个对象又专门挂起一个线程来执行接收客户机发来的消息的循环。还有什么更好的办法么?
      

  2.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
      

  3.   

    对于多连接的情况,最好使用IO completion port,.Net中提供的封装,你可以看看,一个线程对于一个连接是不可取的。
      

  4.   

    IO完成端口可以实现很高的性能,对于你说的500左右连接小菜一碟,.Net中的Socket类提供了现成的封装,就用这个实现
      

  5.   

    搜一搜:异步socket
    500个socket对象不代表就必须用500个线程去接收数据
      

  6.   


    .net中的SOCKET类有提供封装    那它究竟是哪个方法呢?     查MSDN不知道是哪个
      

  7.   

    public bool ConnectAsync(
    SocketAsyncEventArgs e
    )
      

  8.   

    1、服务器端一个Socket实例进行监听,不是连一个客户端创建一个Socket!
    2、使用ManualResetEvent控制线程,异步接收、应答
      

  9.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式
      

  10.   

    还有那些诸如完成端口,以及异步socket什么的,你也许看上去会觉得很复杂,但是那是你还没明白它们的机制,如果你是刚开始接触这个,我建议你先用简单的方法
      

  11.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式

    长连接也不过是占用服务端一个连接对象而已,占用什么线程?
      

  12.   

    难道你服务端侦听客户端数据使用的是N多线程while死循环Recieve吗
      

  13.   

    线程池的话倒不是必须的,如果你想了解。上网收C# 的ThreadPool类。看看这个的用法和介绍
      

  14.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式

    长连接也不过是占用服务端一个连接对象而已,占用什么线程?
    你说的是连接占一个对象,那他为了处理接收数据会发送数据,难道不需要线程,不用线程怎么同时处理多个连接请求?异步?完成端口?他还没理解到这
      

  15.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式

    长连接也不过是占用服务端一个连接对象而已,占用什么线程?
    你说的是连接占一个对象,那他为了处理接收数据会发送数据,难道不需要线程,不用线程怎么同时处理多个连接请求?异步?完成端口?他还没理解到这
    长连接只是保持连接而已,只要你客户端不要不停的给服务端发数据,服务端为什么要不停的用线程接收或发送数据??
    异步也好,或者动态开个线程也好,或者线程池也好,总之没有任何必要维持一个线程什么都不干就在那等数据
      

  16.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式

    长连接也不过是占用服务端一个连接对象而已,占用什么线程?
    你说的是连接占一个对象,那他为了处理接收数据会发送数据,难道不需要线程,不用线程怎么同时处理多个连接请求?异步?完成端口?他还没理解到这
    长连接只是保持连接而已,只要你客户端不要不停的给服务端发数据,服务端为什么要不停的用线程接收或发送数据??
    异步也好,或者动态开个线程也好,或者线程池也好,总之没有任何必要维持一个线程什么都不干就在那等数据
    所以我告诉他用短连接啊。你现在保持了连接状态,又不用线程,那下一次发送的数据服务端怎么接收?
      

  17.   

    大哥,愿闻其详     我才接触多线程和SOCKET不到一个月。很多东西即使查资料都找不到啊。比如长短连接是怎么回事?      线程池是怎么回事?
    长连接就是指一直保持连接状态,哪怕不发送或者接收数据。这种状态肯定要一直占用一个线程。但是如果你发送完数据就关闭。然后下次要发送时再连接,就可以把资源释放了,这样就是短连接的方式,这样线程也只需要短时间的占用。然后配合线程池实现大量的连接。你可以参考一下http协议,http协议就是一种短连接的TCP通信方式

    长连接也不过是占用服务端一个连接对象而已,占用什么线程?
    你说的是连接占一个对象,那他为了处理接收数据会发送数据,难道不需要线程,不用线程怎么同时处理多个连接请求?异步?完成端口?他还没理解到这
    长连接只是保持连接而已,只要你客户端不要不停的给服务端发数据,服务端为什么要不停的用线程接收或发送数据??
    异步也好,或者动态开个线程也好,或者线程池也好,总之没有任何必要维持一个线程什么都不干就在那等数据
    所以我告诉他用短连接啊。你现在保持了连接状态,又不用线程,那下一次发送的数据服务端怎么接收?
    无论长连接还是短连接,服务器端都是一个Socket对象在监听。
    所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持。 
    短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,一般银行都使用短连接。  

    长连接简单点说就是一直保持连接,并非应答之后进行Close,而且维持一个心跳(超过一定时间,进行Close)。
      

  18.   

    http://www.cnblogs.com/chenxizhang/archive/2011/09/10/2172994.html
    看看这个吧.. 看完了什么都懂了...
      

  19.   

    按照某些死板的“范例”,你的所谓500个连接,它会一直使用501个线程来维系,其中一个是处理Accept的,另外500个是处理Receive的。这显然是不对的。因为500个处理Receive的线程把几乎所有时间在干什么?在阻塞!也就是所,线程不是用来处理业务,而是用来“等待”业务发生。你可能会说:我用500个线程在那里等待业务发生、等待10086有人说话、或者等待回拨,只能这样啊?!这是滥用线程的结果。因为有500个会话,那么服务器端一定就有500个TcpClient,但是这是静态的对象,不需要占用线程。只有受到一条消息要进行处理、或者需要发送一个消息时,才需要瞬间使用一个线程执行一下(也就是说让有限个数的CPU可以分时调度、切换一下这些操作)。当系统底层(外设)受到消息时,windows系统从I/O开始最终分配I/O线程来回调你的异步处理方法,而你的异步处理方法可能立刻启动一个工作线程来处理这一条消息(例如它需要80毫秒这么长时间才能处理完)、并立刻释放I/O线程(I/O线程最大可以有1024个以上,64位系统上则多几十倍)。在这之前并不需要占用什么500个线程。你可能看到只有3、4个线程就足以处理500个会话同时访问,因为这个操作依赖于底层回调。说“线程是为了接收数据的,因此需要阻塞、死等”,这显然是不对的。系统会回调你的处理程序,不用你频繁调用(或者死等)系统。搞懂了这个关系,就明白如何避免线程阻塞了。
      

  20.   

    32位系统下,.net的工作线程池最大1024个线程、I/O线程池中也是最大1024个线程。64位系统下,这两个数字大几十倍。就算是只能有5个线程,而且我们用系统线程池来分配线程来处理接收到的消息,那么够不够处理500个同时在线的客户端呢?肯定也够。因为线程池可接收的任务数远远大于最大线程数、它本身就是用来处理“任务队列”的机制,用不着你自己去搞什么队列,也用不着你自己去调度什么队列。所以这也从另外一个侧面说明了,你用不着因为担心队列的复杂机制而用500个线程去“死等”消息。最后要说明一下,在编写服务器程序时,不要使用 Socket,要使用 TcpListener。因为后者是基于windows 的独特的 IOCP机制的,有更好的性能。而前者只是为了跟 linux 的 Socket 机制相兼容而设计的。
      

  21.   

    处理不同消息,也不一定就在不同线程上。任何回调都完全可能跟调用代码是在同一个线程上执行。但是异步操作,本身就是与顺序操作不一样的思维方式!例如我们在网页的 javascript 程序中需要动态地给当前页面的<div id="top"></div>
    ........
    <div id="footer"></div>两个<div>插入html代码(因为这两部分在许多页面都是相同的,因此适合动态插入),考虑到相应的html需要到服务器拉取,为了效率而必须使用并发(而非顺序)处理方式,于是我们的利用jQuery可以写    function LoadTopAndBottom(callback) {
            if (callback === void 0) { callback = null; }        var dtd1 = jQuery.Deferred();
            var dtd2 = jQuery.Deferred();
            BottomLoad(jQuery("#footer"), ".", function () {
                dtd1.resolve();
            });
            TopLoad(jQuery("#top"), ".", function () {
                dtd2.resolve();
            });
            jQuery.when(dtd1, dtd2).done(function () {
                if (callback != null)
                    callback();
            });
        }
    这个函数,基于另外两个异步加载函数(BottomLoad和TopLoad),它们分别在加载完毕时用第二个函数参数进行回调。既然底层是异步的,那么我们就不能假设谁先完成谁后完成,我们只有等待两个异步加载操作完毕之后,才能让 LoadTopAndBottom 方法的回调函数执行。你知道每一个页面中 javascript 能使用到的线程是很少的,所以一般把 javascript 说成是单线程的。但是因为使用了“异步形式”,所以我们就要有这种并发系统的设计思维,就跟顺序程序有不同的程序代码。异步程序设计,跟实际上有没有使用到子线程没有关系,主要是一种与顺序操作不一样的程序设计思维方式而已。
      

  22.   

    C#确实对socket通信做了很多优化和封装,但是你们觉得用异步和IOCP就没有线程么?那只是你们没有维护线程,不代表机器没有帮你开线程。说到底C#封装的还是socket。你们可以看看c++实现这个的时候有你们说的这么轻松么
      

  23.   

    很显然,LoadTopAndBottom 函数执行完毕时,页面的 top 和 footer 根本没有加载完成。在 LoadTopAndBottom 函数内部其实也都是“注册回调操作”。我用一个看起来很低级很原始的javascrip脚本代码来对照你说的“岂不是要挂起500个线程”的说法,这里不在乎编程语言的高低,主要在于编程人员的程序设计思维和知识。你在准备接收处理消息时也是立刻就执行完毕了。不用死等系统消息,系统会使用最适宜的线程来回调你的。
      

  24.   


    那你还可以说“反正代码就是0、1、0、1呢,干脆只要懂得争吵和纠结这两个数字的人就都会编程了!”得了。“用还是没有用”线程、TcpClient 是不是组合了Socket这不是问题的本质,本质是要清楚使用底层的具体流程的“好歹”问题。
      

  25.   

    说白了,
    你的目的不过是为了实现客户端和服务端通信(互相发包裹)
    你不需要研究C#是如何对socket进行封装的(包裹到底用飞机运输还是火车运输)
    也不应该关心它到底使用什么线程(到底是坐这一班飞机还是下一班飞机)
    只要包裹能到达对方手里就好了不是吗??
      

  26.   


    那你还可以说“反正代码就是0、1、0、1呢,干脆只要懂得争吵和纠结这两个数字的人就都会编程了!”得了。“用还是没有用”线程、TcpClient 是不是组合了Socket这不是问题的本质,本质是要清楚使用底层的具体流程的“好歹”问题。
    学习和应用是两回事。难道现在有高级语言就不需要了解底层知识了。既然人家问的是Socket网络编程,很明显就是还在学习这个。你们说不要用Socket。用C#封装的类和机制。但是这是他想要的吗?
      

  27.   


    那你还可以说“反正代码就是0、1、0、1呢,干脆只要懂得争吵和纠结这两个数字的人就都会编程了!”得了。“用还是没有用”线程、TcpClient 是不是组合了Socket这不是问题的本质,本质是要清楚使用底层的具体流程的“好歹”问题。
    学习和应用是两回事。难道现在有高级语言就不需要了解底层知识了。既然人家问的是Socket网络编程,很明显就是还在学习这个。你们说不要用Socket。用C#封装的类和机制。但是这是他想要的吗?
    所以人家问:我想发个快递给别人,应该如何发?
    然后你完全不谈快递公司,而从飞机如何制造,如何创建一个快递公司,如何调度包裹开始讲?
      

  28.   


    才接触到多线程和网络通信教程上的代码是这样的using System.Threading;
    using System.Net;
    using System.Net.Sockets;namespace MyChatSoft
    {
        public partial class ServerFrm : Form
        {
            public ServerFrm()
            {
                InitializeComponent();
                TextBox.CheckForIllegalCrossThreadCalls = false;
            }        #region 显示消息和异常消息
            public void ShowErr(string msg, Exception ex)
            {
                ShowMsg("-----------------begin-------------------------");
                ShowMsg(msg + "" + ex.Message);
                ShowMsg("-----------------end   -------------------------");
            }        public void ShowMsg(string msg)
            {
                txtShow.AppendText(msg + "\r\n");
            }
            #endregion        private void btnStartListen_Click(object sender, EventArgs e)
            {
                StartListening();
            }        //负责监听端口
            Socket sokWelcome = null;
            //负责和客户端Socket通信
            Socket sokConnection = null;
            //负责监听
            Thread threadWatchPort = null;
            //负责接收信息
            Thread threadWatchMsg = null;        #region 初始化并绑定监听
            public void StartListening()
            {
                try
                {
                    //创建IP地址
                    IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
                    //创建IP节点(包含IP和端口)
                    IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
                    //创建监听套接字(寻址协议,流方式,TCP协议)
                    sokWelcome = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    sokWelcome.Bind(endpoint);
                    sokWelcome.Listen(10);//参数:指能同时处理的连接数
                    threadWatchPort = new Thread(WatchPort);
                    //设置为后台线程(当所有前台线程停止后会自动关闭)
                    threadWatchPort.IsBackground = true;
                    threadWatchPort.Start();
                    ShowMsg("开始监听.....");
                }
                catch (Exception ex)
                {
                    ShowErr("", ex);
                }
            } 
            #endregion        #region 监听客户连接请求
            public void WatchPort()
            {
                while (true)
                {
                    try
                    {
                        sokConnection = sokWelcome.Accept();
                        ShowMsg("监听" + sokConnection .RemoteEndPoint.ToString()+ "到连接啦.....");
                        threadWatchMsg = new Thread(RecMsg);
                        threadWatchMsg.IsBackground = true;
                        threadWatchMsg.Start();
                    }
                    catch (Exception ex)
                    {
                        ShowErr("", ex);
                    }
                    break;
                }
            } 
            #endregion        private void RecMsg()
            {
                while (true)
                {
                    try
                    {
                        byte[] byteMsg = new byte[1024 * 1024 * 2];
                        int length = sokConnection.Receive(byteMsg, SocketFlags.None);
                        if (length > 0)
                        {
                            string strMsg = Encoding.UTF8.GetString(byteMsg, 0, length);
                            ShowMsg(strMsg);
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowErr("主机已关闭......", ex);
                    }
                }
           }        private void btnSend_Click(object sender, EventArgs e)
            {
                string strMsg = txtInput.Text.Trim();
                byte[] byteMsg = Encoding.UTF8.GetBytes(strMsg);
                sokConnection.Send(byteMsg, byteMsg.Length, SocketFlags.None);
            }    
        }
    }=====================================================
    根据我对教程这段代码的理解就是  启用一个监听SOCKET,挂起一个循环线程。然后这个线程处于阻塞状态,每次监听到请求  就产生一个用于和客户机通信的SOCKET,然后又使用一个线程,挂起一个循环用于接收客户机发来的消息。。这样似乎就是有多少连接就启用多少了线程。。我也知道多线程不能滥用,但我不知道有什么办法能解决这个问题……所以来问解决方案
      

  29.   


    才接触到多线程和网络通信教程上的代码是这样的using System.Threading;
    using System.Net;
    using System.Net.Sockets;namespace MyChatSoft
    {
        public partial class ServerFrm : Form
        {
            public ServerFrm()
            {
                InitializeComponent();
                TextBox.CheckForIllegalCrossThreadCalls = false;
            }        #region 显示消息和异常消息
            public void ShowErr(string msg, Exception ex)
            {
                ShowMsg("-----------------begin-------------------------");
                ShowMsg(msg + "" + ex.Message);
                ShowMsg("-----------------end   -------------------------");
            }        public void ShowMsg(string msg)
            {
                txtShow.AppendText(msg + "\r\n");
            }
            #endregion        private void btnStartListen_Click(object sender, EventArgs e)
            {
                StartListening();
            }        //负责监听端口
            Socket sokWelcome = null;
            //负责和客户端Socket通信
            Socket sokConnection = null;
            //负责监听
            Thread threadWatchPort = null;
            //负责接收信息
            Thread threadWatchMsg = null;        #region 初始化并绑定监听
            public void StartListening()
            {
                try
                {
                    //创建IP地址
                    IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
                    //创建IP节点(包含IP和端口)
                    IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
                    //创建监听套接字(寻址协议,流方式,TCP协议)
                    sokWelcome = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    sokWelcome.Bind(endpoint);
                    sokWelcome.Listen(10);//参数:指能同时处理的连接数
                    threadWatchPort = new Thread(WatchPort);
                    //设置为后台线程(当所有前台线程停止后会自动关闭)
                    threadWatchPort.IsBackground = true;
                    threadWatchPort.Start();
                    ShowMsg("开始监听.....");
                }
                catch (Exception ex)
                {
                    ShowErr("", ex);
                }
            } 
            #endregion        #region 监听客户连接请求
            public void WatchPort()
            {
                while (true)
                {
                    try
                    {
                        sokConnection = sokWelcome.Accept();
                        ShowMsg("监听" + sokConnection .RemoteEndPoint.ToString()+ "到连接啦.....");
                        threadWatchMsg = new Thread(RecMsg);
                        threadWatchMsg.IsBackground = true;
                        threadWatchMsg.Start();
                    }
                    catch (Exception ex)
                    {
                        ShowErr("", ex);
                    }
                    break;
                }
            } 
            #endregion        private void RecMsg()
            {
                while (true)
                {
                    try
                    {
                        byte[] byteMsg = new byte[1024 * 1024 * 2];
                        int length = sokConnection.Receive(byteMsg, SocketFlags.None);
                        if (length > 0)
                        {
                            string strMsg = Encoding.UTF8.GetString(byteMsg, 0, length);
                            ShowMsg(strMsg);
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowErr("主机已关闭......", ex);
                    }
                }
           }        private void btnSend_Click(object sender, EventArgs e)
            {
                string strMsg = txtInput.Text.Trim();
                byte[] byteMsg = Encoding.UTF8.GetBytes(strMsg);
                sokConnection.Send(byteMsg, byteMsg.Length, SocketFlags.None);
            }    
        }
    }=====================================================
    根据我对教程这段代码的理解就是  启用一个监听SOCKET,挂起一个循环线程。然后这个线程处于阻塞状态,每次监听到请求  就产生一个用于和客户机通信的SOCKET,然后又使用一个线程,挂起一个循环用于接收客户机发来的消息。。这样似乎就是有多少连接就启用多少了线程。。我也知道多线程不能滥用,但我不知道有什么办法能解决这个问题……所以来问解决方案

    解决办法很多,关键看你理解的程度。比如上面他们说的完成端口或者异步SOCKET。你甚至可以直接使用TCPCLIENT类
    教程只是告诉这个东西是怎么用的
      

  30.   


    额。底层知道得不多,不太明白程序上具体应该怎么实施? 用threadpool类?