天天看点

Socket创建C/S模型的小结

           经过一段时间的学习,对于Socket创建C/S模型有了一些心得,写在这里供自己和大家参考。

        一般服务器都要和多个客户端连接通讯,当所有通讯都是TCP连接时,需要服务器和每个客户端保持着连接,并且服务器还要很好的处理将要来的连接请求以及可能会断开的客户。

        1   处理将要来的连接请求(支持关闭套接字):在这里我是专开了一个线程去监听网络,但由于accept函数是阻塞的,所以服务器在关闭时(不再监听网络)就会出异常,后来我在网上找了一下,说select函数可以解决这个问题:select函数就是判断网络有没有连接请求(我让它每毫秒判断一次),如果有则再去accept,没有的话继续判断。具体说明见msdn。我的例子如下:

             sListener.Listen(10);

                Console.WriteLine("Start listen");

                ArrayList listenList = new ArrayList();

                listenList.Add(sLis:ener);

                int i = 0;

                while (true)

                {

                     if (this.ifRun == false)        //服务器可以通过ifRun来关闭监听

                            break;

                     Socket.Select(listenList, null, null, 1000);   //如果网络没有连接请求,Count==0

                     if (listenList.Count == 0){

                            listenList.Add(sListener);

                            Thread.Sleep(1);

                            continue;

                     }

                    Socket handler = sListener.Accept();

                    Console.WriteLine("Come one !");

                    Console.WriteLine(handler.RemoteEndPoint.ToString());

                    Console.WriteLine(handler.LocalEndPoint.ToString());

                    ClassRecv exm = new ClassRecv(handler);    //开辟线程去和该客户端传输数据

                    exm.saveRootPath = this.saveRootPath;

                    Thread t = new Thread(exm.Recv);

                    t.Start();

                }   //while(true)

                //Console.WriteLine("Succeed stop");

                this.sListener.Close();

          2    局域网速度控制(关键是不限速如何确保安全传输)

                 引出问题:

转---------开始

问:  

    如果在局域网内开发一文件传输程序(局域网网卡均为100M),文件被分割成N个包发送的话,使用TCP直接发送,如果我发完一个包不延时的话肯定会丢包。TCP协议不是号称能够避免丢包吗?如果本程序需要在外网上使用,也必须延时吗,那这个延时值应该设置为多少?

答:

  TCP协议不是号称能够避免丢包吗?

---->是保证在传输中不丢包。

但实际上你的问题是在应用层丢了。

TCP有滑动窗口概念,你发的包太多,对方接收缓冲满了,你又不检查错误日志,盲目发,当然有问题,

-----

延时值应该设置为多少?

-----》依据你的网络情况,实际上你不要这样乱发,应该一发一收,收到响应再发下一包,这样可适应任何网络情况。

转---------完

这是网上的人对此问题的一个解释,我看了好多文章,觉得这个文章比较有道理。

我的问题:

    我和上面那兄弟的问题差不多,但是我在接收端加了一个返回消息,照样不行(传的是5m的东西,后面2m就容易出错),我还看了一个不算太标准的ftp服务器的源代码,在不限速的情况下也没有什么特别处理。

       我加了个方法,当接受放给发送法发送返回消息时,先用select函数判断当前socket是否可写----发送,如果不可就sleep(1)循环到可以写。

    结果:程序结构还不好,内存占用太多,发送速度大约是QQ的60%多一点。

测试环境:同一个宿舍的两台机子。

        内存占用问题已经解决,是因为代码写的不太好。 现在副上源代码:

Server(关键部分)

                byte[] recvBuffer = new byte[1024];      //接受文件头信息

                int byteRec = this.handler.Receive(recvBuffer);

                //    Console.WriteLine("Recving Protocol Struct........");

                XmlSerializer structSerializer = new XmlSerializer(typeof(TransStruct));

                MemoryStream stream = new MemoryStream();

                //Received byte to stream

                stream.Write(recvBuffer, 0, recvBuffer.Length);

                stream.Position = 0; //IMP;

                //Call the Deserialize method and cast to the object type

                TransStruct RecvStruct = (TransStruct)structSerializer.Deserialize(stream);

                //Now should recv file

                String name = Path.GetFileName(RecvStruct.filepathName);

                string str = this.saveRootPath + "//" + name;

                FileStream fs = new FileStream(str, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);

                int buffersize = 4 * 1024;                //网络缓冲是8k(不知道写得是否标准)

                byte[] fileBytes = new byte[buffersize];  

                int i = 0;

                ArrayList listenList = new ArrayList();      //

                string strT = "&&&&";

                byte[] strTB = new byte[4];

                while ((RecvStruct.FILESIZE - i) >= buffersize)    //接收文件

                {

                    int n =this.handler.Receive(fileBytes);

                    //fileBuffer.AddRange(fileBytes);

                    i += fileBytes.Length;

                    fs.Write(fileBytes, 0, fileBytes.Length);

                    //select

                    listenList.Add(this.handler);

                    Socket.Select(listenList, null, null, 1000);

                    while (listenList.Count == 0)

                    {

                        listenList.Clear();

                        listenList.Add(this.handler);

                        Socket.Select(null, listenList, null, 1000);

                        Thread.Sleep(1);

                    }

                    strTB = Encoding.ASCII.GetBytes(strT);

                    this.handler.Send(strTB);

              }

              if ((int)(RecvStruct.FILESIZE - i) > 0)   //看文件有没有最后一小部分没有传输完成

              {

                  byte[] lastBuffer = new byte[(int)(RecvStruct.FILESIZE - i)];

                  this.handler.Receive(lastBuffer);

                  fs.Write(lastBuffer, 0, lastBuffer.Length);

                 // fileBuffer.AddRange(lastBuffer);

              }

                //fileBytes = new byte[fileBuffer.Count];

                //fileBuffer.CopyTo(fileBytes);

                fs.Write(fileBytes, 0, fileBytes.Length);

                fs.Flush();

                fs.Close();

                // Configration.FileReceived++;

                handler.Shutdown(SocketShutdown.Both);

                handler.Close();

Client:

      没什么特别的,和Server相对应。

    新问题:

       我对于异常处理还没有完全掌握,要作出一个稳定的系统,必须做好它。 我的传输速度(在不限速的情况下)大约是QQ,ftp的60%多,但是已经不出错了。 目前主要考虑稳定性,所以速度先放一下。看过ftp客户端源代码,并没有返回之类的判断,所以速度快。关键问题在于ftp服务器是怎么做的。