已阅读5页,还剩76页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Socket 开发之通讯协议及处理 在 Socket 应用开发中,还有一个话题是讨论的比较多的,那就是数据接收后如何处理 的问题。这也是一个令刚接触 Socket 开发的人很头疼的问题。 因为 Socket 的 TCP 通讯中有一个“粘包”的现象,既:大多数时候发送端多次发送 的小数据包会被连在一起被接收端同时接收到,多个小包被组成一个大包被接收。有时候 一个大数据包又会被拆成多个小数据包发送。这样就存在一个将数据包拆分和重新组合的 问题。那么如何去处理这个问题呢?这就是我今天要讲的通讯协议。 所谓的协议就是通讯双方协商并制定好要传送的数据的结构与格式。并按制定好的格 式去组合与分析数据。从而使数据得以被准确的理解和处理。 那么我们如何去制定通讯协议呢?很简单,就是指定数据中各个字节所代表的意义。 比如说:第一位代表封包头,第二位代表封类型,第三、四位代表封包的数据长度。然后 后面是实际的数据内容。 如下面这个例子: 01 01 06 00 01 0f ef 87 56 34 协议 类别 协议代码 数据 长度 实际数据 前面三部分称之为封包头,它的长度是固定的,第四部分是封包数据,它的长度是不 固定的,由第三部分标识其长度。因为我们的协议将用在 TCP 中,所以我没有加入校验位。 原因是 TCP 可以保证数据的完整性。校验位是没有必要存在的。 接下来我们要为这个数据封包声明一个类来封装它: 1 public class Message 2 3 private byte _class; 4 private byte _flag; 5 private int _size; 6 private byte _content; 7 8 public byte Content 9 10 get return _content; 11 set _content = value; 12 13 14 public int Size 15 16 get return _size; 17 set _size = value; 18 19 20 public byte Flag 21 22 get return _flag; 23 set _flag = value; 24 25 26 public byte Class 27 28 get return _class; 29 set _class = value; 30 31 32 public Message() 33 34 35 36 37 public Message(byte class, byte flag, byte content) 38 39 _class = class; 40 _flag = flag; 41 _size = content.Length; 42 _content = content; 43 44 45 public byte ToBytes() 46 47 byte _byte; 48 using (MemoryStream mem = new MemoryStream() 49 50 BinaryWriter writer = new BinaryWriter(mem); 51 writer.Write(_class); 52 writer.Write(_flag); 53 writer.Write(_size); 54 if (_size 0) 55 56 writer.Write(_content); 57 58 _byte = mem.ToArray(); 59 writer.Close(); 60 61 return _byte; 62 63 64 public static Message FromBytes(byte Buffer) 65 66 Message message = new Message(); 67 using (MemoryStream mem = new MemoryStream(Buffer) 68 69 BinaryReader reader = new BinaryReader(mem); 70 message._class = reader.ReadByte(); 71 message._flag = reader.ReadByte(); 72 message._size = reader.ReadInt32(); 73 if (message._size 0) 74 75 message._content = reader.ReadBytes(message._size); 76 77 reader.Close(); 78 79 return message; 80 81 82 我们可以用 Tobytes()和 FromBytes()将封包转换成二进制数组和从二进制数组转 换回来。 事情看起来已经解决了,但真的是这样子吗?不然,我们知道,TCP 数据是以流 的形式被传送的,我们并不知道一个数据包是否被传送完毕,也不知道我们接收回来的数 据包中是否有多个数据包,如果直接使用 FromBytes()来转换的话,很可能会因为数据不 完整而出现异常,也有可能会因为数据中含有多个数据包而导致数据丢失(因为你并不知 道这些数据中含有多少个数据包)。那我们该怎么办?这也不难,我们先把接收回来的数 据写入一个流中。然后分析其中是否有完整的数据包,如果有,将其从流中取出,并将这 部分数据从流中清除。直到流中没有完整的数据为止,以后接收回来的数据就将其写入流 的结尾处,并从头继续分析。直到结束。 让我们来看看这部分的代码: 1 public class MessageStream 2 3 private byte _buffer; 4 private int _position; 5 private int _length; 6 private int _capacity; 7 8 public MessageStream() 9 10 _buffer = new byte0; 11 _position = 0; 12 _length = 0; 13 _capacity = 0; 14 15 16 private byte ReadByte() 17 18 if (this._position = this._length) 19 20 return 0; 21 22 return this._bufferthis._position+; 23 24 25 private int ReadInt() 26 27 int num = this._position += 4; 28 if (num this._length) 29 30 this._position = this._length; 31 return -1; 32 33 return (this._buffernum - 4 | (this._buffernum - 3 count) 40 41 num = count; 42 43 if (num = 0) 52 53 buffernum2 = this._bufferthis._position + num2; 54 55 56 else 57 58 Buffer.BlockCopy(this._buffer, this._position, buffer, 0, num); 59 60 this._position += num; 61 return buffer; 62 63 64 public bool Read(out Message message) 65 66 message = null; 67 _position = 0; 68 if (_length 6) 69 70 message = new Message(); 71 message.Class = ReadByte(); 72 message.Flag = ReadByte(); 73 message.Size = ReadInt(); 74 if (message.Size 0) 77 78 message.Content = ReadBytes(message.Size); 79 80 Remove(message.Size + 6); 81 return true; 82 83 else 84 85 message = null; 86 return false; 87 88 89 else 90 91 return false; 92 93 94 95 private void EnsureCapacity(int value) 96 97 if (value 0) 106 Buffer.BlockCopy(this._buffer, 0, buffer1, 0, this._length); 107 this._buffer = buffer1; 108 this._capacity = num1; 109 110 111 public void Write(byte buffer, int offset, int count) 112 113 if (buffer.Length - offset = count) 126 127 Buffer.BlockCopy(_buffer, count, _buffer, 0, _length - count); 128 _length -= count; 129 Array.Clear(_buffer, _length, _capacity - _length); 130 131 else 132 133 _length = 0; 134 Array.Clear(_buffer, 0, _capacity); 135 136 137 这个类的使用非常简单,你只要用 Write(byte buffer, int offset, int count)将接收 到的数据写入数据流中,并用 bool Read(out Message message)将数据中的第一个数据包取 出,如果函数返回 True,就说明取回一个封包成功,如果返回 False,则说明流中已经没 有完整的封包,你需要继续接收后面的数据以组成一个完整的封包。 这们我们的数据分析就会变得非常简单。我们可以在 ReceiveCallBack 回调函数中 将接收到的数据写入到流中并通知线程池中的工作者线程分析数据流并处理数据。我在前 面的关于 Socket 异步操作的文章中的 Analyzer 函数就是用这两个类来分析处理数据的。 这样的好处理就是,Socket 工作线程只需要负责数据的接收,并将其写入流,其它的事 情由其它的线程这处理,就不会因为处理的时间过长而导致接收操作被阻塞。从而影响 Socket 的性能。 本文所述方法只是协议处理的多种方法中的其中一种,而且可能并不是很优秀的方法,如 果谁有更好的方法,还希望您能和我多多交流。好了,今天就到这里了,关于 Socket 的文 章到这里可能就告一段落了,我现在在研究 VS2008 里面的新东西,如果有什么必得的话, 我会继续写出来的。谢谢大家的支持。 posted on 2007-12-24 00:34 牧野 阅读(2816) 评论(26) 编辑 收藏 所属分类: C# 、Socket 评论 #1 楼 2007-12-24 07:41 兰亭 好文章,浅显易懂 回复 引用 查看 #2 楼 2007-12-24 08:40 学者 不错啊 牧野朋友 好久不见啊 ! 回复 引用 查看 #3 楼 2007-12-24 08:50 学者 这个类的使用非常简单,你只要用 Write(byte buffer, int offset, int count)将接收到的 数据写入数据流中,并用 bool Read(out Message message)将数据中的第一个数据包取出, 如果函数返回 True,就说明取回一个封包成功,如果返回 False,则说明流中已经没有完整的 封包,你需要继续接收后面的数据以组成一个完整的封包。 牧野 这句话我有点疑惑 如果一个包在网络上丢失了 TCP 会不会 叫发送端重新发送这个丢失的数据包呢? 如果一直 发不成功 该怎么处理,要不要加时间校验啊? 回复 引用 查看 #4 楼 楼主 2007-12-24 08:55 牧 野 学者 这个问题 TCP 协议层已经为我们处理过了,所以我们不需要再关注这个问题。TCP 是一个可 信任的连接,它可以保证数据按发送顺序到达并保证数据的完整到达。 回复 引用 查看 #5 楼 2007-12-24 09:02 学者 谢谢 要是服务器端的那个流一直不满 是不是一直等下去啊 ?有可能出现这样的事啊! 回复 引用 查看 #6 楼 楼主 2007-12-24 09:06 牧 野 学者 如果流中没有一个完整的数据包,好像我们除了等下去之外也没有什么事可以干哦。呵 呵 回复 引用 查看 #7 楼 2007-12-24 09:11 学者 我觉得应该加上一个服务器端的缓冲的一个时间校验 到了时间 如果还没有到 就把整个数据 都丢弃啊 不然 在很差的网络 会严重占用服务器的啊 呵呵 只是揣测啊 !有啥问题请指正! 回复 引用 查看 #8 楼 2007-12-24 09:22 大石头 真是又见牧野,呵呵。 这篇文章非常精彩。 我也曾经因为这个问题苦恼过。我的一个程序向网站服务器发出 HTTP 请求,服务器返回数据 的时候,我是异步形式处理的,来一个数据包触发一次,根本不知道什么时候是收完整个网页 内容。不知道你有什么好主意。 另外,上次的 keepalive 完美的解决了我的代理无名错误的问题,用上后,再也没有错过了。 回复 引用 查看 #9 楼 2007-12-24 09:25 大石头 学者 我的做法是这样的,在建立接收对方数据的异步的时候,同时建立一个 Timer,把异步委托的 句柄传进去,如果到时间了异步还没有完成,也就是没有收到任何数据,则 Timer 会把这个异 步给取消了的。 回复 引用 查看 #10 楼 楼主 2007-12-24 09:30 牧 野 大石头 HTTP 你可以去分析 HTTP 的头部字段,其中就有一个 Content-Length 字段,它标识的是整 个 HTML 文件的长度。你就只要接收到的数据达到 Content-Length 标识的长度就可以了, 当然,它不包括 HTTP 头的长度。 回复 引用 查看 #11 楼 楼主 2007-12-24 09:31 牧 野 学者 这个如果要做的话也应该在 Socket 接收模块中处理哦,我这个可是协议分析和处理。呵 呵 回复 引用 查看 #12 楼 2007-12-24 09:34 学者 感谢 牧野 和大石头! 回复 引用 查看 #13 楼 2007-12-24 10:11 驿路梨花 我以前也遇到过类似的问题,当时要是看到了这篇文章就好多了。当时我专门为那些问题研究 过 TCP UDP IP FTP 等协议,自已写过一个类似 QQ 的东西还做过一个 FTP。 回复 引用 查看 #14 楼 2007-12-24 15:51 qqq 未注册用户 学习 回复 引用 查看 #15 楼 2007-12-24 17:34 大石头 牧 野 有些网站,就是没有那个字段,郁闷。 回复 引用 查看 #16 楼 楼主 2007-12-24 17:42 牧 野 大石头 不会吧,我还没碰到哪个 Web 服务器会不发送这个字段啊。 回复 引用 查看 #17 楼 2008-01-09 17:13 Sleet 未注册用户 牧 野 我想请问一下 MessageStream 用在异步通讯时,如果有多个客户端连接,且它们有可能在同一个时间同时 发送数据上来,这时是一个 MessageStream 应对一个 Socket 还是一个 MessageStream 就对多个 Socket 来处理?如果是一对多的情况下,会不会出现,A 客户端发送上来的数据包 很大,被拆成了多个数据包,而 B 也是这种情况,而导致 A 的数据包还没组装完毕就被接上 B 的数据包? 谢谢你的文章,看了学了很多 回复 引用 查看 #18 楼 楼主 2008-01-09 17:16 牧野 Sleet 你好,要一个流对应一个 Socket。 回复 引用 查看 #19 楼 2008-01-09 17:18 Sleet 未注册用户 牧野 十分感谢你的及时回答,哈哈 回复 引用 查看 #20 楼 2008-01-19 10:21 CXP 未注册用户 01 01 06 00 01 0f ef 87 56 34 协议类别 协议代码 数据长度 实际数据 十分感谢牧野的这篇文章? 如果我想发送文件,那应该在什么位置上标识文件名? 应该有多少位来标识文件名呢? 还有。我不是很明白 01(协议类型)的用处, 在实际应用当中“协议类别“ 用来标识什么东西?TCP UDP 以上的实例都是用 TCP 协议来实现,所以我感觉有点迷惑! 希望牧野能回答我这些问题。!谢谢! 回复 引用 查看 #21 楼 2008-02-12 01:25 何镇汐 未注册用户 return (this._buffernum - 4 | (this._buffernum - 3 Join xx 表示某人加入, priv 发送者 接收者 内容 它上面把这些命令用|分割开,比如 priv|发送者|接收者|内容,然后打到一个数组中处理,我 感觉这种方法不够灵活,不知道实际开发中怎么定义这些命令呢,是不是加在消息头中? 敬请高手指教! 回复 引用 查看 #23 楼 2008-02-22 16:39 鸿鹄 未注册用户 斑竹 你好! 我想向你请教一个问题,关于 socket 的 关于动态添加端口进行多端口监听。如 果你知道怎么实现希望能告诉我 谢谢。 回复 引用 查看 #24 楼 2008-05-22 11:23 airwolf2026 -引用- 牧 野 : 大石头 不会吧,我还没碰到哪个 Web 服务器会不发送这个字段啊。 - web 服务器可以用 chunk 块模式发送数据的.这个时候就没有 content-length 字段了 回复 引用 查看 .NET Socket 开发之异步 Socket 在基于.NET 的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步 Socket 了。 异步 Socket 的性能比同步高出很多,但是编写代码比较复杂。因此异步 Socket 也是网络上 讨论比较多的话题。 今天,我们就来讨论一下如何用异步 Socket 开发网络应用。在此之前我们先讨论两个问题。 一、异步 Socket 是如何工作的: 那异步 Socket 是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投 递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到 达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲 区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。 二、什么情况下我们用异步 Socket: 有些人认为,异步 Socket 的性能比同步 Socket 的性能高很多,应该在各种环境下都用异 步 Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这 样呢? 、 客户端 Socket。 、 服务端连接数比较少。 、 连接数很多,但都是短连接。 在这些环境下,我们用同步 Socket 不但可以简化代码,而且性能并不会比异步 Socket 低。 但在服务端连接比较多而且是长连接的情况下,我们就要使用异步 Socket。 现在我们来看看如何用异步 Socket 编程。 首先,我们要建立一个 Socket 用来监听: Socket _listener = new Socket(AddressFamily.InterNetwork, SocketTyp e.Stream, ProtocolType.Tcp); IPEndPoint localEP = new IPEndPoint(_address, _port); _listener.Bind(localEP); _listener.Listen(100); 然后创建一个线程来处理客户端连接请求: Thread _acceptWorkThread = new Thread(AcceptWorkThread); _acceptWorkThread.Start(); private void AcceptWorkThread() while (_isListener) UserInfo info = new UserInfo();/这个 UserInfo 是用来保存客户信息的。 info.socket = socket; Socket socket = _listener.Accept(); /这里进行其它处理。 socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);/这里向系统投递一个接收信息的请求,并为其指定 ReceiveCallBack 做为回调函数 我们再来看看回调函数的定义: private void ReceiveCallBack(IAsyncResult ar) UserInfo info = (UserInfo)ar.AsyncState; Socket handler = info.socket; int readCount = 0; try readCount = handler.EndReceive(ar);/调用这个函数来结束本次接收并返 回接收到的数据长度。 catch (SocketException)/出现 Socket 异常就关闭连接 CloseSocket(info);/这个函数用来关闭客户端连接 return; catch if (readCount 0) byte buffer = new bytereadCount; Buffer.BlockCopy(info.Buffer, 0, buffer, 0, readCount); Analyzer(info, buffer);/这个函数用来处理接收到的信息。 try handler.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFla gs.None, new AsyncCallback(ReceiveCallBack), info);/向系统投递下一个接收请求 catch (SocketException) /出现 Socket 异常就关闭连接 CloseSocket(info); catch else /如果接收到 0 字节的数据说明客户端关闭了 Socket,那我们也要关闭 Soc ket CloseSocket(info); 接下来我们看看如何发送数据给客户端: public void Send(Socket socket, byte message) try info.socket.BeginSend(message, 0, _byte.Length, SocketFlags.None, new AsyncCallback(Se ndCallBack), info);/这里向系统投递一个发送数据的请求,并指定一个回调函数。 catch (SocketException ex) CloseSocket(info); catch 定义发送回调函数: private void SendCallBack(IAsyncResult ar) UserInfo info = (UserInfo)ar.AsyncState; try info.socket.EndSend(ar);/调用这个函数来结束本次发送。 catch 好了,整个监听、接收、发送的过程就完成了,很简单吧。现在需要说明的是,我在这里接 收客户端连接的 Accept 是用的同步的,我个人认为在这里用同步的会比用异步好一些。因为这 样代码简单而且没有性能上的损失。 今天我就写到这里了!下次我们再继续。 posted on 2007-06-13 23:59 牧野 阅读(4969) 评论(47) 编辑 收藏 所属分类: C# 、Socket 评论 #1 楼 2007-06-14 08:36 嘻嘻 未注册用户 写的不错! !11 回复 引用 查看 #2 楼 2007-06-14 11:24 老钟 未注册用户 通过捕获错误来关闭连接会导致性能问题,建议 使用: Socket.BeginReceive (Byte, Int32, Int32, SocketFlags, SocketError, AsyncCallback, Object) Socket.EndReceive (IAsyncResult, SocketError) 来获取错误号也许性能会好一些 回复 引用 查看 #3 楼 2007-06-15 19:10 biaobiao 未注册用户 楼主对异步的认识大错特错 所谓的 SOCKET 采用异步会取得高效的性能说的就是 Accept。我们应该用 BeginAccept, 因为如果用 Accept 的话,同时连接数量多的情况下就不能及时回应,而用 BeginAccept 就会 很好的避免这个问题,所谓的 SOCKET 应该采用异步来提高性能,其实说的就是我们应该用 BeginAccept。对于 SEND 和 RECEIVE,你只要开一个线程在处理一个连接其实就相当于是 BEGINSEND 和 BEGINRECEIVE,就是在异步处理了。有人说一个新连接开一个线程不好, 如果有 1000 连接就要开 1000 个线程,所以应该采用异步,这简直就是天大的笑话,这些笨 蛋们远不知道 BEGINSEND 等方法就是在线程池开的线程来处理。 BEGINSEND 和 BEGINRECEIVE 在。NET1.1 里根本就没有这两个方法,难道。NET1.1 的 SOCKET 就不能异步了?看了楼主的文章,其实很多东西楼主大大的理解错了。 回复 引用 查看 #4 楼 楼主 2007-06-15 19:33 牧 野 biaobiao 那你有没有查看过.NET 的类库呢? 呵呵 BeginSned 和 BeginReceive 可不是简单的丢在线程池里,他是投递到系统内核里去了。由 系统内核来调度发送和接收的操作。 还要告诉你一点,在 Socket 编程中,线程不是越多越好,你知道性能最高的 IOCP 模式有多 少个线程吗?CPU 数量22,就这么多。当一个程序的线程达到 50 个以上时,如果再增加线 程,系统的性能会下降很多!看来你还要多学学! 你使用 BeginAccept 来接收 Socket,而用 Receive 和 Send 来收发数据,这才是大错特错。 回家好好看完书再来讨论。 还有,不要在我这里骂人,不然我会删除你的回复。那些被你骂成笨蛋的恰恰是比你更了解 Windows 开发的人。 回复 引用 查看 #5 楼 楼主 2007-06-15 19:34 牧 野 老钟 你的建议不错,回去把例子的代码改一下,到时发上来给大家看看! 回复 引用 查看 #6 楼 楼主 2007-06-15 19:40 牧 野 biaobiao 还有一点,.NET1.1 里面的 Socket 有 BeginSend 和 BeginReceive 这两个方法,建议你多 看看 MSDN。 回复 引用 查看 #7 楼 2007-06-15 20:36 biaobiao 未注册用户 呵呵,你要这样理解异步你就这样理解吧,我是给出正确的解释。你做过实际的项目吗?你了 解 TCP/IP 吗? 回复 引用 查看 #8 楼 楼主 2007-06-16 08:49 牧 野 biaobiao 我从事软件开发年,做过的项目不下二十个,其中有一半涉及到网络开发! 小伙子,谦虚一点!多看点书。 回复 引用 查看 #9 楼 2007-06-16 09:00 忍 未注册用户 顶, 收藏 回复 引用 查看 #10 楼 2007-06-16 10:07 gussing 正常交流很有趣,吵的越凶越好,当事人和观众都会有很大的收获。相互攻击就很无聊了,一 方摆做过实际项目的臭脸,另一方摆年纪大经验足的老架子,有这份闲心不如把.NET 网络相 关的东东更深入的给我们讲讲,不是更有意义? 回复 引用 查看 #11 楼 楼主 2007-06-16 10:27 牧 野 gussing 呵呵 谢谢你的关注,我可没摆老架子,我只是告诉他,我做过实际项目,这些都是我做项目的时候 总结出来的经验,可不是想当然想出来的! 呵呵 你的建议很好,我也准备再写一些相关的东东! 回复 引用 查看 #12 楼 楼主 2007-06-16 10:27 牧 野 biaobiao 删除你一篇回复,因为我说过不要在我这里骂人! 回复 引用 查看 #13 楼 楼主 2007-06-16 10:32 牧 野 biaobiao 我的垃圾代码就在上面,不知道你的不是垃圾的代码在哪呢? 如果你再不沉下心来和我争论技术而是骂人的话,我这里不欢迎你! 回复 引用 查看 #14 楼 2007-06-16 10:35 biaobiao 未注册用户 删回复,你这个人好虚伪,我的那个回复肯本就没带一个骂人的字,这个你很清楚,你太虚伪 了。呵呵,你就按照你的想法做吧。说实话,你上面的代码能拿来见人,真的好笑。 回复 引用 查看 #15 楼 楼主 2007-06-16 10:40 牧 野 biaobiao 我说过,我这里不欢迎你了!如果你不讨论技术问题的话。 说别人是笨蛋,别人的代码是垃圾,这不算骂人吗? 不知道阁下的代码能不能拿出来见人呢? PS:如果再出现非技术回复,一律删除! 回复 引用 查看 #16 楼 2007-06-16 14:37 biaobiao 未注册用户 呵呵,把我回复都删除了吧。 回复 引用 查看 #17 楼 楼主 2007-06-16 14:54 牧 野 biaobiao 我欢迎技术的争论,但不欢迎骂人,我不删除你全部的回复是因为你没被删除的回复是关于技 术的。 回复 引用 查看 #18 楼 2007-06-17 11:41 哈哈 未注册用户 biaobiao 异步 Socket 不是简单的起多个线程 你测试一下就知道了 1200 的并发 实际上 系统分配给接收 Socket 的线程数 大约只有 30-50 个 回复 引用 查看 #19 楼 2007-06-18 10:56 嘻嘻 未注册用户 biaobiao 说话不要太刻薄,牧 野 这样做也是有他的道理的。 你如果不服气 你可以自己写啊 。别人写了 你来 JJYY 的成何体统。 回复 引用 查看 #20 楼 2007-06-18 16:38 gussing 牧 野 “性能最高的 IOCP 模式有多少个线程吗?CPU 数量22“ 我很想知道该公式是怎么来的,能否告知一二?谢谢 回复 引用 查看 #21 楼 楼主 2007-06-20 14:23 牧 野 gussing 这个公式是前人的经验总结出来的! 回复 引用 查看 #22 楼 2007-06-21 15:32 刘易斯 未注册用户 开发新手,借鉴代码。多谢! 还想请教个问题。 服务器开两个端口监听。 一个端口(8091)监听接收的是长时间不断的连接,每来一个连接,都要把它存入哈希表 ht. 另一个端口(8092)监听的连接都是短连接,客户端发完消息就关闭连接。然后服务器从哈 希表 ht 中取出一个连接,将消息转发出去. 8091 端口对应的客户端多,可能上千。 8092 对应的客户端可能几百。 8092 端口的客户端我用同步收发. 服务器两个端口的收发,各应该用异步还是同步? 希望指教! 回复 引用 查看 #23 楼 楼主 2007-06-21 19:44 牧 野 刘易斯 可以分别使用同步和异步,互相并不会影响。 回复 引用 查看 #24 楼 2007-06-29 15:09 红金鱼 未注册用户 牧野 的这篇文章没啥错的,我赞同他的观点,尤其是关于异步的好处,它绝非简单的把 Socket 操 作抛到线程池里(我在刚开始用.NET 1.0 的时候也有过这种想法),而是传给里系统内核,然后系 统内核会把它最终传到硬件层,这时候用到的线程甚至根本不是 CPU 上的,而是通讯硬件中的, 这种手法可以大量节约 CPU 资源. 还有就是关于线程的使用,应该尽量节约,尤其是在做有大量客户连接的服务器时,最好是一两个 线程负责所有的客户请求. 我自己用的方法是把所有客户请求抛到一个队列里,有一个线程负责 把请求从队列里取出来处理. 它好处有两个: 1. 节省并发线程 2. 是避免了多线程并发处理请求时的线程同步. 如果对异步 Socket 有疑惑,可以读下大师 Jeffrey Richter 的, 其中有一章讲 .NET 线程和异步操作,比 MSDN 讲的透彻. 最后说一下,我做开发的年头和数量不在作者之下,以上所说主要来自具体编程的实践体会. 回复 引用 查看 #25 楼 2007-07-24 14:14 yellowyu 终于得出一个结论了,其实讨论问题,争吵问题是很正常的,可骂人就不对了,还在学习,谢 谢红金鱼与牧 野!BIAOBIAO 如果牛叉的话,就搞个反面例子出来,大家一起分享啦 回复 引用 查看 #26 楼 2007-08-03 09:04 yooono 未注册用户 没做过 Socket 不敢乱说话。 回复 引用 查看 #27 楼 2007-08-04 10:20 边城浪 未注册用户 牧野写得不错. 不过我还是仅同意 biaobiao 服务器端用 BeginAccept 可能性能更好,虽然是复杂了一点点 例外如按老钟说的改用 Socket.EndReceive (IAsyncResult, SocketError) 不用还会不会有异常抛出? 回复 引用 查看 #28 楼 2007-08-04 15:13 边城浪 未注册用户 可以参考 基于事件的异步 Socket(TCP 连接方式) /yeerh/archive/2006/09/25/1280111.aspx 很久以前的了按老钟的说法改用了 SocketError,性能应该更好了些. 回复 引用 查看 #29 楼 2007-08-06 15:57 边城浪 未注册用户 再问一下Socket 断线后 是否可以自动重连 下面是连接程序 我想在网络断开的时候重新连,怎么改,谢谢 加注释的话异常是在已连接的 socket 申请连接 public void Connect2Server() IPAddress ipAddress = IPAddress.Parse(szSvrIPAddr); EndPoint remoteEP = new IPEndPoint(ipAddress, SvrPort); /* Socket SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); if (SocketClient.Connected) SocketClient.Shutdown(SocketShutdown.Both); SocketClient.Close(); Thread.Sleep(100); */ while(!SocketClient.Connected) try SocketClient.Connect(remoteEP); catch(Exception exc) Log.WriteEntry(“Connect to Server Error:“ + exc.Message, EventLogEntryType.Error, 2); Thread.Sleep(30 * 1000); /30s 回复 引用 查看 #30 楼 2007-09-05 11:31 Good_NEt 未注册用户 牧 野 大哥,Demo 在哪呢? 能否提供下载,或者 Send me (Csharp_) 谢谢了! 回复 引用 查看 #31 楼 2007-09-05 11:33 Good_NEt 未注册用户 对了,帮忙把我的回复的改成 AT. 这样就不会有 恶意/广告 邮件了.谢谢/.嘿嘿 回复 引用 查看 #32 楼 2007-09-21 10:16 寻找鱼 未注册用户 楼主 借你宝地一用哦 因为这里做 网络的高手比较多 来这里问问题,也比较容易解决 我的问题是 类似 QQ 登陆界面网络设置中的代理登陆功能如何实现 期待好心人的帮忙 QQ:305804380 回复 引用 查看 #33 楼 2007-10-22 00:21 cct 未注册用户 请问一下客户端和同步,服务端用异步行不行 我客户端的连接,发送数据都用同步,而服务端用异步,但当我发送第一个数据头的时候只有 5 个字节 ,服务端可以马上接收到调试,可以执行我定义的事件,但我在发第二个 数据的时候,服务端就不执行我自定义的事件,真是奇怪 回复 引用 查看 #34 楼 楼主 2007-10-22 08:33 牧 野 cct 这样做是可以的,因为 Socket 并不会管对方用的是什么模式。 你出这样的问题我也不清楚具体的原因。 回复 引用 查看 #35 楼 2007-10-24 14:02 Ocean.Juxta 未注册用户 牧 野 我觉得你的代码还有些问题没有解决 首先,tcp 的边界问题并没有处理,这样做放到广域网肯定会出错的,这个就不多说了 其次,线程池数量是有限的,你只是用异步处理完全依靠了 ThreadPool.而他只提供了 25 个 工作线程和 1000 个 IO 线程,那么在接受几千上万的连接时,IOCP 线程肯定忙不过来(因为 你将处理逻辑 Analyzer(info, buffer);/完全占用了 IOCP 线程) 回复 引用 查看 #36 楼 楼主 2007-10-27 21:19 牧 野 Ocean.Juxta Analyzer(info, buffer);就是用来处理 TCP 边界问题的,并且把处理好的数据发送给工作线 程处理。 所以你说的这些问题都是不存在的! 回复 引用 查看 #37 楼 2007-10-31 17:00 Boooob 未注册用户 cct 为了性能 socket 有 缓冲算法 ,所以发出的时间是不能完全确定的 不过你可以关闭缓冲算法 回复 引用 查看 #38 楼 2007-11-21 02:01 MIR 未注册用户 好啊。太
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 眼科白内障手术医师考试试卷及答案
- 胭脂鱼人工繁育管护技师考试试卷及答案
- 2025年黑龙江省五大连池市高二生物下册期末考试模拟卷必考附答案
- 2026年四川省都江堰市高二生物下册期末考试考试卷带答案(能力提升)
- 2026年江西省瑞昌市高二生物下册期末考试模拟卷附答案(满分必刷)
- 2025年江西省樟树市高二生物下册期末考试模拟卷及一套答案
- 2026年湖南省醴陵市高二生物下册期末考试模拟卷及完整答案【各地真题】
- 2026年河北省霸州市高二生物下册期末考试测试卷(精练)附答案
- 2026年吉林省珲春市高二生物下册期末考试测试卷含答案【夺分金卷】
- 九年级语文阅读理解万能答题公式专项练习题及参考答案(中考专用)
- 2026年哈尔滨市萧红中学六年级下语文6月月考试题及答案0612
- 2026年高考真题-语文(全国二卷) 含解析
- 2026年湖南岳阳市初二学业水平地生会考真题试卷(含答案)
- 2026春人教版三年级下册语文全册看拼音写词语专项练习(可打印)
- 2026年外贸应聘人员测试题及答案
- 2026云南临沧国投宏华招聘综合业务开单员3人备考题库附答案详解(典型题)
- 市政管线迁改施工方案
- 西安铁路局集团有限公司招聘笔试题库2026
- 学堂在线 医学英语词汇进阶 期末考试答案
- MySQL数据库应用实验训练参考答案
- 人教版六年级数学上册各单元知识点专项训练练习题及易错题专项训练题含答案解析
评论
0/150
提交评论