asp.net用socket发送自定义报文,包括报文头长度,报文头,报文体长度,报文体。对如何发送和接收搞不好了,还请大家帮看看,谢谢

shjsmhkd 2017-04-11 02:18:15
如题
服务器端

int port = 6000;
string host = "127.0.0.1";

IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);

Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sSocket.Bind(ipe);
sSocket.Listen(0);
Console.WriteLine("监听已经打开,请等待");

//receive message接收
Socket serverSocket = sSocket.Accept();
Console.WriteLine("连接已经建立");
string recStr = "";
byte[] recByte = new byte[4096];
int bytes = serverSocket.Receive(recByte, recByte.Length, 0);
recStr += Encoding.ASCII.GetString(recByte, 0, bytes);//接收报文
//接收报文长度的感觉意思代码如下行
//要求发过来的长度是2字节二进制格式
int sh2 = System.BitConverter.ToInt16(recByte, 0);
//这是字节转int,但好像不是二进制的字节转的呀?
//执行得到不是想要的,只是个意思


//send message发送
Console.WriteLine("服务器端获得信息:{0}", recStr);

// recStr接收到的
//想要把接收到的报文,包括报文头长度,报文头,报文体长度,报文体原封不动再发回客户端
string sendStr = recStr;
byte[] sendByte = Encoding.ASCII.GetBytes(sendStr);
serverSocket.Send(sendByte, sendByte.Length, 0);
serverSocket.Close();
sSocket.Close();


客户端

int port = 6000;
string host = "127.0.0.1";//服务器端ip地址

IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);

Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(ipe);

//报文头长度和报文头内容
string _header = "{"mode":"0"}";//报文头内容,拼接json格式,mode为0报文 不加密,为1报文 加密
short _len = (short)_header.Length;//报文头长度

//send message发送
//报文头长度要求为2字节二进制格式,这里主要是我不会的了
byte[] bslen = new byte[2];//定义2字节
bslen = BitConverter.GetBytes(_len);//二进制格式,这里也是意思,这样好像不是二进制
或这样
// bslen = Encoding.GetEncoding(936).GetBytes(Convert.ToString(_len, 2));//感觉这样是二进制了

//报文体
string bodyTpl =
@"
<Root>
<Head>
<Trxcode>{0}</Trxcode>
<count>{1}</count>
</Head>
</Root>";
string Trxcode = "中文";//交易代码
string count = "您好";//记录数量
string body = string.Format(bodyTpl, Trxcode, count);

//报文体长度
short _len2t = (short)body .Length;//报文头长度
//报文体长度要求为2字节二进制格式,这里主要是我不会的了
byte[] bslen2t = new byte[2];//定义2字节
bslen2t = BitConverter.GetBytes(_len2t);//二进制格式,这里也是意思,这样好像不是二进制
或这样
// bslen = Encoding.GetEncoding(936).GetBytes(Convert.ToString(_len2t, 2));//感觉这样是二进制了

byte[] bsheader = Encoding.ASCII.GetBytes(_header);

byte[] bsbody = Encoding.ASCII.GetBytes(body);

//这里是分开发送的,这样对吗?服务器端如何接收,这又是我不会的了
clientSocket.Send(bslen);
clientSocket.Send(bsheader);

clientSocket.Send(bslen2t);
clientSocket.Send(bsbody);

//或者合在一起发
//byte[] zh = Encoding.GetEncoding(936).GetBytes(Convert.ToString(_len, 2) + _header +Convert.ToString(_len2t, 2) + body);
// clientSocket.Send(zh);
//但这样不能用BitConverter.GetBytes(_len)这样了,总之就是倒底如何长度是2字节二进制格式
//还有就是如果长度不用2字节二进制格式,就是一个数值,那要如何发送,是分开发?还是合在一起发,搞晕了
//接收时,合在一起发的就截取,但是以字符串还是byte[],有区别吗,以byte[]怎以截取?
//分开发的,又怎么分开接收呢?

//receive message接收。客户端发出后,服务器端再原封不动发回来接收
string recStr = "";
byte[] recBytes = new byte[4096];
int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
recStr += Encoding.ASCII.GetString(recBytes, 0, bytes);
Console.WriteLine(recStr);

clientSocket.Close();

上述服务器端和客户端建立通信,在互相发送一次信息后通信便结束,这个没有关系的

我的问题:
一,发送自定义报文,包括报文头长度,报文头,报文体长度,报文体。要怎么发送?一般发送一段字符串,就是字符串转byte[]后直接发了,但有长度,有头,有体是怎么发,就是没理解了。是分开发,还是合一起发?合一起长度怎么表示,主要是长度是2字节二进制格式。(随便问下,长度就是正常的数值,会有发送的上区别吗)。还请给出代码,最好是2字节二进制格式和就数值 两种,谢谢

二,正常发送后,怎么接收?我的代码只用了
byte[] recByte = new byte[4096];
int bytes = serverSocket.Receive(recByte, recByte.Length, 0);
recStr += Encoding.ASCII.GetString(recByte, 0, bytes);//接收报文
这是统一接收了吧?那要怎么区分长度,头和体呢?
网上有说先取前两个字节,看看长度,就确定了后面头和体截取多长了?但我就不会怎么先取前两个字节呢?还请给出代码,谢谢

三,客户端是分开发,还是合一起发?
如分开
clientSocket.Send(bslen);
clientSocket.Send(bsheader);
合一起发
//byte[] zh = Encoding.GetEncoding(936).GetBytes(Convert.ToString(_len, 2) + _header +Convert.ToString(_len2t, 2) + body);
// clientSocket.Send(zh);
这有什么样的区别?应当用那种呢?

4,合一起发的话,长度是2字节二进制格式和头与体怎么在一起表示啊?还请给出代码,谢谢

5,分开发的话,我发现我的服务器端只接收了两次,如
clientSocket.Send(bslen);//收到
clientSocket.Send(bsheader);//收到

clientSocket.Send(bslen2t);//没收到了
clientSocket.Send(bsbody);//没收到了
这应当是我服务器端写的不对造成的,但请能讲讲原理吗?谢谢

6,如用BitConverter.GetBytes(_len)这样发对的,我长度如102,但接收后变为f了
recStr += Encoding.GetEncoding(936).GetString(recByte, 0, bytes);//这样接的

如用// bslen = Encoding.GetEncoding(936).GetBytes(Convert.ToString(_len2t, 2));接到1100110这个一共7位表示102的字符串
这要怎么解决呢,还请给出两种情况的代码,谢谢

汇总
长度2字节二进制格式与头,体怎么发送?
怎么接收时先取前2字节得到长度,2字节二进制格式与数值有区别吗
完整的自定义报文,长度,头,体,怎么发送,分开发?还是合一起发?
分开或合一起发后,怎么相应的接收?

总之就是一个自定义报文,有长度,头,体。长度想要2字节二进制格式,怎么发送和接收?发送是怎么前2字节是长度结合头与体?接收是怎么先取前2字节得到长度,再取到头和体?

还请给出代码,谢谢
...全文
847 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
江南小鱼 2017-04-28
  • 打赏
  • 举报
回复
我是来看评论的,正文回复都是长篇大论啊,mark一下。
  • 打赏
  • 举报
回复
接收消息“是”使用 Receive,发送消息“是”使用 Send。但是许多人为什么成为标题党?为什么被不良培训者欺骗呢?就是因为把这个逻辑给理解“反了”!他以为只要是 Receive 就收到了完整消息,他把必要条件当做成充分条件,他不知道其实那些培训连入门都没有入门,因为没有告诉你程序设计方法,而只是告诉你一些简单语法而已。 我们从 tcp 角度来看看 http post 消息基本格式。在消息“头”的最后,有两个连续的 0d 0a 字节,然后是消息“体”,然后又是两个连续的 0d 0a 字节。只有当看到这样的信令格式,才开始解析这个恶 http 消息。 所以任何消息都有信令格式设计,最基本的知识要求。不是说你“随便发”、另一端“随便收”,就能学会通讯程序设计。最起码地要知道自己定义消息格式,在另一端能解析为完整的消息。 而 tcp 接收端(不管是服务器还是客户端)都是应该连续接收数据,处理分包,判断是否接收到一个完整消息。这应该记为一个常识知识。
  • 打赏
  • 举报
回复
引用 10 楼 shjsmhkd 的回复:
aspx是能收的,我测试通过,就是aspx发多次时,服务器端返回多次,可aspx只接收一次,想请问有什么方法,aspx也可以接收多次??
不论是服务器端,还是客户端,接收消息都要处理分包情况,都是接收多次。不管所谓的 buffer 设置多大,不管是设置1M 还是1 byte,都需要处理分包(并不是设置越大越好,当然也不是设置为小于10k更好)。而你 Receive 一次,这显然是错误的流程。处理分包、多次 BeginReceive/Receive,解析消息,判断有没有收到一条完整的消息,只有等到收到了完整消息之后才能说处理消息并且发送返回值。 不管是短连接还是长连接 tcp 通讯,都要处理分包问题。不能忽视分包。对于你的短链接tcp 方式来说,“客户端”多次 Receive ,然后当收到了一条完整的返回消息,处理了收到的消息,就可以关闭连接了。这样服务器端也随后关闭了连接,所以服务器端并不需要关闭连接(或者其实也可以规定最长连接时间,超时则中断连接)。
  • 打赏
  • 举报
回复
aspx 基本上是处理浏览器请求时使用,asp.net (以及 IIS)其实经常会重启你的 asp.net 应用程序的另一个进程,来解决许多问题。所以 asp.net 进程经常结束,各种内存中的状态数据经常丢失,你的程序的相关内容也会丢失。 从你的问题中的代码来看,你的“服务器端”Accept 一次,然后 Receive 一次,然后不管是不是分包的部分信息,都把这个当作完整的字符串(仅仅是字符串)执行 Console.WriteLine 输出,然后 Send 一个信息,然后就关闭服务。从这个来看,基本上是一些专门摆着让你了解一些基本语法的小例子上的代码。正常的服务流程根本不是这样的。正常的服务可以 BeginAccept/Accept 上万、几十万的请求,然后获得请求之后每一个单独的信道可以单独进行 BeginReceive/Receive 而想互不干扰,并且可以处理分包信息(而不是假设每一次 Receive 的信息都是完整的消息),并且 Send 返回数据是在消息解析中的事情(解释是在异步子线程中)而并不阻塞 BeginReceive/Receive(并不等待处理完消息Send完返回值才开始)。实际上也不轻易关闭服务。 从你的“客户端”来看,基本上你的客户端不是 web 概念。你是在 asp.net 服务器上当作客户端来看待,并不是在浏览器客户端。 通讯中要处理分包的情况,也就是接收到的信息都要放到一个 List<byte> 集合中,然后每一次 Receive 之后都要检查、解析一下这个集合的 byte[ ] ,判断是否存在一个完整的消息。例如假设你的信令规定了“第一个字节是消息长度”,那么你就从这个 byte[ ] 的第一个字节来判断一下有没有足够长度的 byes;或者比如说有的信令约定用 0d、0a 两个字节表示消息结束。当你解析到一条完整的消息,才能进行处理。你不能在收到了不完整的 bytes 的时候就随便地执行 Encoding.XXXX.GetString(....) 这种操作。
by_封爱 2017-04-28
  • 打赏
  • 举报
回复
哎,. 你既然都玩socket了. 你就应该知道 socket跟http(asp.net)有什么区别, asp.net(web) 中是不能随便收发tcp/ip的... 因为他是长连接..http是短连接...这最起码的 你应该懂吧..(如果这你不懂那你没有继续看下去的必要了) 首先我们不说你具体协议如何..反正也没人看..只说流程. 你无非是想通过asp.net后台发送 socket 到"服务端(虽然我不知道你的服务端是不是也是"网页")".然后根据服务端的返回值做处理 明确的告诉你,那是不行的... 因为http在请求之后就没了...所以这个时候 你服务端可能还没有send 但是这个时候 tcpclient已经释放了 根本保持不了.. 就算服务端在收到数据马上send 这个时候 也不一定能发过来..更何况这样做根本没意义..这根本就是"短链接"干的事. 长连接是无论何时的 都可以进行收发,否则他的存在也没有意义啊...更何况真正的项目中 这些东西都是异步的... 既然说到"无论何时" 那么显然 http是办不到的... 所以现在你就研究协议报文这种东西 对你来说 还是太早了..因为你连基本的"流程" 可能都不太清楚. 更何况你还让大家直接给你写出代码.....
xdashewan 2017-04-28
  • 打赏
  • 举报
回复
引用 10 楼 shjsmhkd 的回复:
aspx是能收的,我测试通过,就是aspx发多次时,服务器端返回多次,可aspx只接收一次,想请问有什么方法,aspx也可以接收多次??
web和服务器多次通信,要么轮询要么websocket
shjsmhkd 2017-04-28
  • 打赏
  • 举报
回复
引用 9 楼 diaodiaop 的回复:
aspx只能发 不能收.... 收的叫"服务端" 应该是一个exe 或者一个服务..而不是"网页"
aspx是能收的,我测试通过,就是aspx发多次时,服务器端返回多次,可aspx只接收一次,想请问有什么方法,aspx也可以接收多次??
by_封爱 2017-04-25
  • 打赏
  • 举报
回复
aspx只能发 不能收.... 收的叫"服务端" 应该是一个exe 或者一个服务..而不是"网页"
shjsmhkd 2017-04-25
  • 打赏
  • 举报
回复
还想请问大家个事,就是socket我用的是个asapx页面,不是一个应用程序,如果服务器那边是分开发的,比如发了三次,那我的一个aspx页面怎么接收三次呢,我试了下,只能接一次啊。 这个大家方便给个代码吗?谢了
shjsmhkd 2017-04-21
  • 打赏
  • 举报
回复
还想请问大家个事,就是socket我用的是个asapx页面,不是一个应用程序
hiose89 2017-04-18
  • 打赏
  • 举报
回复
引用 5 楼 shjsmhkd 的回复:
[quote=引用 2 楼 hiose89 的回复:] 不知道你做网站为什么要这种需求。 监听和接收都需要不停调用,要不然下次有人连你,你就连不上了。 用多线程来搞。 如果你要区别着发,就要做个标识,要不然收到后你也没办法知道是头还是体。 一次性发也是需要做手脚来标示。 再不则我感觉最好做的就是把对像直接发过来,反正你全是字符,都是简单的类型。 直接弄成对象 序列化发过来 收到再反序列化就行了。 我是这样觉得。
请问怎么做个标识,又怎么根据标识区分,主要是区分多段数据时,一段数据包括长度,头,体,多段时如何判断? 最好有几条代码,谢谢 [/quote] 标示这种东西任何方法都可以实现,你可以自己加一些特殊字符来区分,也有更简单来的做法。 比如JSON 就是KEY VALUES的格式。你现在的光有VALUES 所以你不知道哪一个是头哪一个是体, 当你给相应的值 加上标示键后就可以区分了啊。 接收后反序列化一下就成对象了。
shjsmhkd 2017-04-18
  • 打赏
  • 举报
回复
引用 2 楼 hiose89 的回复:
不知道你做网站为什么要这种需求。 监听和接收都需要不停调用,要不然下次有人连你,你就连不上了。 用多线程来搞。 如果你要区别着发,就要做个标识,要不然收到后你也没办法知道是头还是体。 一次性发也是需要做手脚来标示。 再不则我感觉最好做的就是把对像直接发过来,反正你全是字符,都是简单的类型。 直接弄成对象 序列化发过来 收到再反序列化就行了。 我是这样觉得。
请问怎么做个标识,又怎么根据标识区分,主要是区分多段数据时,一段数据包括长度,头,体,多段时如何判断? 最好有几条代码,谢谢
xdashewan 2017-04-13
  • 打赏
  • 举报
回复
引用 3 楼 shjsmhkd 的回复:
还有就是我发了如三次,一长度,二头,三体,这三个是一个数据的总共。我再发一个数据的总共,接收时怎么判断是新的一个数据了呢??
socket这个东西不是你发几次就一定要收几次的,你可以发N次,但只要你接受的buff足够大,完全可以一行就收完,所以无需去在于收发次数。第一次收2个长度字节,然后解析得到后续还有多少数据需要接收,然后去收这点长度的数据,反复收,每收一次计算剩余长度,直到长度吻合未知。然后再接受2个长度字节,重复上述操作
shjsmhkd 2017-04-13
  • 打赏
  • 举报
回复
引用 1 楼 xdashewan 的回复:
随便你怎么发,一起发也行分几次发都行。对于这种自定义协议的报文,可以先收2个长度字节,然后根据得到长度再去收后续字节,有多段就以此类推
没太明白您说的,如果分几次发,第一次接收是长度,然后怎么接第二次后续字节呢? 请问能给个代码吗?谢了 还有就是我发了如三次,一长度,二头,三体,这三个是一个数据的总共。我再发一个数据的总共,接收时怎么判断是新的一个数据了呢??
hiose89 2017-04-11
  • 打赏
  • 举报
回复
不知道你做网站为什么要这种需求。 监听和接收都需要不停调用,要不然下次有人连你,你就连不上了。 用多线程来搞。 如果你要区别着发,就要做个标识,要不然收到后你也没办法知道是头还是体。 一次性发也是需要做手脚来标示。 再不则我感觉最好做的就是把对像直接发过来,反正你全是字符,都是简单的类型。 直接弄成对象 序列化发过来 收到再反序列化就行了。 我是这样觉得。
xdashewan 2017-04-11
  • 打赏
  • 举报
回复
随便你怎么发,一起发也行分几次发都行。对于这种自定义协议的报文,可以先收2个长度字节,然后根据得到长度再去收后续字节,有多段就以此类推

62,025

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

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