一、技术概述
1.1 基于TCP/IP的通信技术
基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和用户端两部分。
第一部分 服务器端
一、创建服务器套接字(create)。
二、服务器套接字进行信息绑定(bind),并开始监听连接(listen)。
三、接受来自用户端的连接请求(accept)。
四、开始数据传输(send/receive)。
五、关闭套接字(closesocket)。
第二部分 用户端
一、创建用户套接字(create)。
二、与远程服务器进行连接(connect),如被接受则创建接收进程。
三、开始数据传输(send/receive)。
四、关闭套接字(closesocket)。
1.2 .NET 平台下几种SOCKET模型的简要性能参考(摘抄)
(1)Socket + Threads/ThreadPool
实现:Accept一个Socket,就交给一个线程去管理,比较笨,但也比较有效,因为是同步方式,控制起来很方便。高级点的,就是交给一个线程池去管理,线程池由系统自动托管,省去了开销线程的时间。一般小型项目,用这个完全足够,开发也简单。但要注意,如果若干Socket长时间占用线程池中的线程,同时其它连接数又比较多,很容易出现提示说你没有足够的线程供使用。呵呵,让Socket少做点事,少占用时间,换一个快点的CPU是不错的方式。另外,如果有一些比较好的第三方线程池组件,也可以选择使用,比如SmartThreadPool。
(2)Socket + Select
实现:Select是很常用的一种模型。是在阻塞功能中轮询一个或多个Socket,将要处理的Socket放到一个IList中,当Select轮询结束后,然后我们再自己处理这个IList中的Socket。具体的用法可以看一下MSDN。Select的效率并不能说是高的,因为当队列中待处理的Socket比较多的时候,处理最后几个Socket相当于要遍历所有前面的Socket,非常不划算的。
(3)Socket + Asynchronous
实现:BeginXXXX,EndXXXX,再熟悉不过了吧。异步Socket归根到底,还是用的线程池技术,用线程池来处理异步IO。这就又引出个问题,.NET的线程池又是用的什么实现方式,以前看过有人说,.NET的线程池是用的完成端口来实现的,我不知道这样的说法是不是正确,从查到的资料中也没有办法确认(希望这点有朋友可以告诉我)。异步Socket对于程序的处理流程来说比同步复杂了许多,异步回调函数的控制不如同步方式那样直观。但有一点我想应该是要注意的,就是回调函数应该轻装上阵,不应该处理过多的事务,对传递数据的处理,应该交给其它线程进行处理。
(4)IOCP(完成端口)
实现:现在.NET下有一些伪IOCP,还没有见过开放出来的用这些伪IOCP来实现的SOCKET例子。我说的20000~50000个客户端连接,是指在C++下开发的情况,这样的情况下,需要用到的基本技术还包括内存池、查询算法等
基于目前阶段的综合考虑选择用多线程Socket+thread但是也用到线程池里的一些方法。
1.3 多线程技术
我们可以把线程看成是一个进程(执行程序)中的一个执行点,每个进程在任何给定时刻可能有若干个线程在运行。一个进程中的所有线程共享该进程中同样的地址空间,同样的数据和代码,以及同样的资源。进程中每个线程都有自己独立的栈空间,和其它线程分离,并且不可互相访问。每个线程在本进程所占的CPU时间内,要么以时间片轮换方式,要么以优先级方式运行。如果以时间片轮换方式运行,则每个线程获得同样的时间量;如果以优先级方式运行,则优先级高的线程将得到较多的时间量,而优先级低的线程只能得到较少的时间量。方式的选择主要取决于系统时间调度器的机制以及程序的实时性要求。
二、具体的实现方法如下:
初始化:当启动工作的时候create 套间字,bind绑定端口,listen监听端口,在监听listen函数有一个参数是监听同时连接的最大个数。如listen(10);当多个GPRS客户端连接的时候要进行排队。然后 accept连接请求。监控是一个线程,线程函数是一个死的循环。可以一直在监听客户端的连接。主要的代码:
private void acceptclient()
{
while (true)
{
if (s != null)
{
try{
temp = s.Accept();//为新建连接创建新的Socket。
……
socketthread.Add(temp);
i++;
ThreadPool.QueueUserWorkItem(new WaitCallback(recdata), socketthread[i - 1]);
ThreadPool.QueueUserWorkItem(new WaitCallback(senddata), socketthread[i - 1]);
}
catch (Exception err){
// MessageBox.Show(err.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}}
ip = ((IPEndPoint)temp.RemoteEndPoint).Address.ToString();
this.richTextBox1.Text += "GPRS:"+ip+"已经连接"+"\r\n";
tempdata = 1;
}
}
当有连接的时候的会用到线程池ThreadPool类的函数启动一个接受线程同时将此时的SOCKET参数传输到启动的线程里(异步回调机制)。接受线程中的线程函数也是一个死的循环,可以接受GPRS客户端发送过来的数据;当再有一个连接的时候会再启动一个接受线程不断的接受GPRS客户端发送来的数据,当断开的时候SOCKET为NULL线程结束。依次下去…如果同时几个GPRS客户端连接的时候,listen函数里有参数,可以对同时连接的客户端监听并对其自动排队。主要的代码:
private void recdata(Socket ss)
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
while(true)
thread技术 {
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
if (ss == null)
{
this.richTextBox1.Text = "ffer";
break;
}
try
{
……
bytes = ss.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
recvStr = System.Text.UTF32Encoding.Default.GetString(recvBytes, 0, bytes);
}
catch (Exception err)
{
// MessageBox.Show(err.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
break;
}
}
public void recdata(object ss)
{
data((Socket)ss);
}
发送线程函数如下:
private void senddata(Socket tt)
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论