socket 编程,recv缓存,编码转换如何处理半截编码?

pqcst 2018-12-14 04:24:04
服务器端是utf-8编码,要转换为ANSI编码。
recv()缓存大小,设置为1024。

utf-8下中文字符可能占三个字节,比如“文”的十六进制编码为E69687,E6 出现在上一个缓存,9687出现在下一个缓存。


我想到的方法有两种:
一)识别出完整的编码,把半截编码留到后面,跟下一段一起解码转换。问题是,代码复杂,工作量大增。这条路有什么简洁的解决方案吗?

二)将本地缓存做大,收完信息一起解码。问题是,对于比较大的信息,内存开销较大。

请问各位高手都有什么更好的解决方案或者改进方法吗?

谢谢!
...全文
492 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2018-12-26
  • 打赏
  • 举报
回复
《http权威指南》
pqcst 2018-12-25
  • 打赏
  • 举报
回复
现在剩下的一个未解之谜,就是正常html文件结尾,这个东西怎么来的? <html> <head><title>400 Bad Request</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <hr><center>nginx/1.2.8</center> </body> </html>
赵4老师 2018-12-25
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket
send(人多)send(病少)send(财富)
recv(人多病)recv(少财富)
陷阱里面啊!
http://bbs.csdn.net/topics/380167545

了解一下google protobuf
pqcst 2018-12-25
  • 打赏
  • 举报
回复
引用 39 楼 赵4老师 的回复:
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545 了解一下google protobuf
赵老师,您提供的那个帖子我翻完了,好热闹! 中间夹杂数字的问题找到了,应该不是多线程发送的问题! sina的网页,有的是Transfer-Encoding: chunked,有的不带。 我找的第一页不带chunked,所以没有注意到这个问题。 下面这个帖子有比较详细的描述。 https://cloud.tencent.com/info/3555e5e9ac8eadf44cef14719c317ff7.html 大概这样的:Transfer-Encoding: chunked字段可以看出响应体是否为 chunked 压缩,chunked 数据很有意思,采用的格式是 长度\r\n内容\r\n长度\r\n..0\r\n,而且长度还是十六进制的,最后以 0\r\n 结尾(不保证都有)。
赵4老师 2018-12-24
  • 打赏
  • 举报
回复
如果服务端使用多个线程发送数据,比如一个线程发送\xAA\xBB\xCC三个字节,另一个线程发送比如心跳包\r\n****\r\n,那么你就可能收到:
\xAA\r\n****\r\n\xBB\xCC

而且
\xAA\r\n****\r\n\xBB\xCC是在一次recv得到的流片断中。
你不要以为你一定会一次recv收到\r\n****\r\n
pqcst 2018-12-24
  • 打赏
  • 举报
回复
引用 37 楼 赵4老师 的回复:
如果服务端使用多个线程发送数据,比如一个线程发送\xAA\xBB\xCC三个字节,另一个线程发送比如心跳包\r\n****\r\n,那么你就可能收到: \xAA\r\n****\r\n\xBB\xCC 而且 \xAA\r\n****\r\n\xBB\xCC是在一次recv得到的流片断中。 你不要以为你一定会一次recv收到\r\n****\r\n
那这样的话,我如何做过滤呢? 我看了下http请求的参数,好像也没有指定单线程的,并且这样对服务器端来说也不划算。 但是我看浏览器里面,是没有这些干扰信息的,它们成功地解决这个问题。 我有个思路,就是使用getline,前后都没有标头或尖括号的单行就是干扰信息。 不知道这样的过滤条件是否会误杀,也不知道有没有更好的处理方法。 请赵老师指点
赵4老师 2018-12-22
  • 打赏
  • 举报
回复
不抓包不调试tcp通信。
pqcst 2018-12-22
  • 打赏
  • 举报
回复
引用 27 楼 赵4老师 的回复:
"GET /favicon.ico HTTP/1.1" 404 -
赵老师,这个favicon的请求是默认的吗? 但是我只调用了一次send()函数啊
pqcst 2018-12-22
  • 打赏
  • 举报
回复
引用 35 楼 赵4老师 的回复:
wireshark 发送时只用同一个线程
赵老师,我使用microsoft network monitor 看到了所有的包。 发现我想服务发送的GET请求只有一个,没有关于favicon或者其他的请求。但是正常传输结束后,还是有个400的回应。 从服务器发来的信息看,payload都挺长,没有那种“\r\n2000\r\n"的单独包。但是我确实收到了这样的信息。 是不是我分析抓包的方式不对?
赵4老师 2018-12-22
  • 打赏
  • 举报
回复
wireshark
发送时只用同一个线程
pqcst 2018-12-22
  • 打赏
  • 举报
回复
引用 32 楼 赵4老师 的回复:
不抓包不调试tcp通信。
fiddler好像不行 我换了microsoft network monitor 正在查包,不过还请赵老师直到一下,在编码断,我如何把来自不同线程的包区分开?
pqcst 2018-12-22
  • 打赏
  • 举报
回复
引用 32 楼 赵4老师 的回复:
不抓包不调试tcp通信。
好的,我下载了一个fiddler 但是它不能抓我自己写的程序的数据包 网上搜了半天也没有解决方案 赵老师能指点下吗? 谢谢了
pqcst 2018-12-21
  • 打赏
  • 举报
回复
引用 29 楼 赵4老师 的回复:
如果服务端使用多个线程发送数据,比如一个线程发送\xAA\xBB\xCC三个字节,另一个线程发送比如心跳包\r\n****\r\n,那么你就可能收到: \xAA\r\n****\r\n\xBB\xCC
我觉得就是您说的这个情况。 这个问题确实是因网站而异的。 我用recv函数只能接到两个线程数据包合并的结果, 请问赵老师,如何才能更深入一层区分两个不同来源的数据包呢?
赵4老师 2018-12-21
  • 打赏
  • 举报
回复
如果服务端使用多个线程发送数据,比如一个线程发送\xAA\xBB\xCC三个字节,另一个线程发送比如心跳包\r\n****\r\n,那么你就可能收到:
\xAA\r\n****\r\n\xBB\xCC
pqcst 2018-12-21
  • 打赏
  • 举报
回复
引用 26 楼 赵4老师 的回复:
看网站源代码 和 抓包 不是一回事!
赵老师,我看网站源代码是为了看服务器端有什么信息流过来,看出问题的点在服务器端是什么信息。 我发现sina.blog 的问题都是在一个3位汉字UTF8编码之间,加入一个"\r\n****\r\n"(中间4位数字或字母,看起来应该是16进制表示)。这个其实不用看源代码了,在服务器端,一个汉字之间是不可能夹杂一个字符串的。 赵老师的意思是,这个片段确实不是来自于我想要请求的目标网页,但是还是通过某个包来到了我的socket,我要把这个包抓到?
赵4老师 2018-12-21
  • 打赏
  • 举报
回复
"GET /favicon.ico HTTP/1.1" 404 -
赵4老师 2018-12-21
  • 打赏
  • 举报
回复
看网站源代码

抓包
不是一回事!
pqcst 2018-12-21
  • 打赏
  • 举报
回复
引用 21 楼 赵4老师 的回复:
有可能。 不抓包不调试tcp通信。
赵老师,我看了网站的源代码,里面是找不到2000 8000 的。 说明服务器发过来的时候在正常的信息里面掺了其他信息,这好像不太可能啊?
pqcst 2018-12-21
  • 打赏
  • 举报
回复
引用 22 楼 northwesternwind 的回复:
[quote=引用 19 楼 pqcst 的回复:] [quote=引用 17 楼 northwesternwind 的回复:] [quote=引用 16 楼 northwesternwind 的回复:] 看了你的代码,send和recv函数的返回处理应该是很不严密。先找一找别的资料,学习一下这两个函数的正确用法。然后修改代码。不用再胡乱猜测别的什么原因。
仔细研究了一下你的代码,是利用socket去下载文件。首先你的代码有两个问题: 1. 因为你把缓冲区都作为字符串处理,所以在每次recv之前必须利用memset把szRecvBuf,szUTF8Buff全部清零。否则会 有垃圾数据影响后面的操作。 2. 你的while(1)循环终止条件有问题。因为这是http协议返回的,你应该根据response中的长度指示,接受完成就退出循环,不是等出错了才结束循环:

Content-Length: 72838
服务器已经通知你会发送的数据长度了。但是被你无视。 3. 更重要的,如果是http协议操作,为啥不使用现成的库?你自己实现的很麻烦而且漏洞百出。可以参考这个帖子: http://www.cnblogs.com/highway-9/p/6021238.html[/quote] 谢谢您抽出时间来帮忙解决问题! 1. 这个我昨天意识到了,所以在recv()返回字节少于缓存长度的时候,我在有效信息最后一位加'\0' 解决,之前用memset(0)做过处理,但是不能解决中间正常字符流不能解码的问题; 2. 确实应该使用这个信息更好一些,我马上在程序里更改一下。 3. 因为我之前没有接触过网络编程,这个项目更多是个学习过程。并且现在这个是为了辅助自己的工作,不是商业项目,所以没有太考效率问题。等我把这个过程走下来,再回头用您推荐的库来优化一下。[/quote] 除了网页内容之外,http协议还会发送一些额外的信息,比如200 OK之类的http应答。你是用socket自己实现http的通讯过程。所以对于socket接收的数据,要按照http协议去解析。 当然2000,8000这些具体是什么,你已经把接收到的完整数据保存到文件里了,打开看看大概就知道是怎么回事了。[/quote] 老兄,能不能再帮我看一个问题^^ 还是上面的代码,我建立一次连接,发送一个请求(keep-alive),会连续返回两个html信息,一个是我想要的网页源代码,最后还会返回一个很短的html,返回400,提示非法请求。 这是什么情况啊。
赵4老师 2018-12-20
  • 打赏
  • 举报
回复
有可能。
不抓包不调试tcp通信。
加载更多回复(22)

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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