关于数据传输,Post到服务器的数据直接输出就变了

枫0子K 2017-02-18 12:46:11
客户端:C# 服务端:PHP
场景:客户端有个文件存放用户数据,想将它压缩后发送到服务端保存,然后其他客户端通过向服务端请求获取文件数据替换本地文件。实现用户数据同步。

服务端代码:(很简单的拿到数据就输出)

<?php
$txt = $_POST['data'];
echo $txt;
?>

客户端代码:

string url = "http://localhost:8080/am_sync_data.php";
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "abc.txt");
string path1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "abc1.txt");

var data = File.ReadAllBytes(path);
//var txt = File.ReadAllText(path);

// 采用.NET提供的GZipStream压缩
var comData = GZipUtils.Compress(data);

using (WebClient client = new WebClient())
{
// 构造传输参数,压缩数据转换未Base64字符串
var value = Convert.ToBase64String(comData);
var param = string.Format("data={0}", value);

client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var resStr = client.UploadString(url, param);
// Base64字符串转换回压缩数据
var resData = Convert.FromBase64String(resStr);

File.WriteAllBytes(path1, resData);
}

出现的问题:
1. 使用文本对比工具对比了原始文件和保存后的文件,发现存在差异。(大小相同)
2. 将byte[]数据转换为字符串输出到文件进行对比,发现大部分字节是相同的,少量出现不对,怀疑是特殊字符到服务端后被识别错了。
3. 如果不经过压缩直接传输是没问题的,但是数据量就大了很多,实不可取。

请教的问题:
1. 是C#的问题还是PHP的问题,或者代码如何改进?(只要能实现场景描述即可)
2. 关于场景描述中提到的同一用户多客户端间的数据同步应该是很常见的,想了解下有没有优秀的方案可参考下?
...全文
265 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
枫0子K 2017-02-18
  • 打赏
  • 举报
回复
引用 7 楼 Forty2 的回复:
base64的字符有A-Z,a-z,0-9共62,再加上’/‘和 ’+‘后正好凑足64个。 base64编码的结果是3的倍数,不够的部分用’=‘号来填充字符。 而在UrlEncode编码下,’/‘,’+‘和’=‘都是保留字符,需要转义。 你把base64作为application/x-www-form-urlencoded发送是不对的。 二进制中,一个字节可以表示256种状态;而64进制中,一个字节只能表示64种状态。 因此base64编码比二进制需要更多的字节。byte[300],编码成base64,需要400个字节(填充后为402个字节)。
给你个6666你能接受么,哈,很专业。
枫0子K 2017-02-18
  • 打赏
  • 举报
回复
引用 6 楼 shingoscar 的回复:
[quote=引用 4 楼 Yokeqi 的回复:] [quote=引用 2 楼 shingoscar 的回复:] base64里有加号,到服务器上就变空格了,自己用负号或下划线之类的替换下就行了
对比出问题的地方确实是+号变成了空格,你有没有成熟的替换用例呢。[/quote] value = value.Replace("+", "-"); resStr = resStr.Replace("-", "+"); 替换下也不会么。。。[/quote] 这个当然是会的,结合7楼的解释,其实就很明白了。这里看起来除了处理+号,还要处理/号。我所问的替换用例就是怕只处理+号而遗漏了还有其他的特殊字符。我在网上搜了下相关问题,已经明白怎么处理了。 非常感谢!
  • 打赏
  • 举报
回复
嗯,我刚刚看到 #3 楼已经说明白了。
  • 打赏
  • 举报
回复
对于二进制数据传送,不要使用 application/x-www-form-urlencoded 之类的协议。用它反而是多此一举的。 硬要个别参数可以放到 url 参数中。例如:
var filename = "九阴真经";
new WebClient().UploadData("http://www.abc.com/upload?f=" + HttpUtility.UrlEncode(filename), comData);
这样就行了。 个别参数放到 url 参数中,而消息体直接放二进制信息内容。不用转来转去地耗费时间。
  • 打赏
  • 举报
回复
引用 楼主 Yokeqi 的回复:
场景:客户端有个文件存放用户数据,想将它压缩后发送到服务端保存
如果你使用这种(如楼上所说)application/x-www-form-urlencoded协议,那么你的数据不仅仅是 string,还必须经过了 UrlEncode。也就是类似
    var value = HttpUtility.UrlEncoide( Convert.ToBase64String(comData));
这样的处理,才能当作 post 数据。 这是你对协议中的“数值”理解不正确造成的。 假设你的服务器端将整个 Request Body 作为数据,其实更好。那么你在客户端就简单地写
new WebClient().UploadData("http://localhost:8080/am_sync_data.php", comData);
就行了。 可见你的服务器设计太复杂了,反而要弄一个 data 参数,多此一举。
Forty2 2017-02-18
  • 打赏
  • 举报
回复
base64的字符有A-Z,a-z,0-9共62,再加上’/‘和 ’+‘后正好凑足64个。 base64编码的结果是3的倍数,不够的部分用’=‘号来填充字符。 而在UrlEncode编码下,’/‘,’+‘和’=‘都是保留字符,需要转义。 你把base64作为application/x-www-form-urlencoded发送是不对的。 二进制中,一个字节可以表示256种状态;而64进制中,一个字节只能表示64种状态。 因此base64编码比二进制需要更多的字节。byte[300],编码成base64,需要400个字节(填充后为402个字节)。
Poopaye 2017-02-18
  • 打赏
  • 举报
回复
引用 4 楼 Yokeqi 的回复:
[quote=引用 2 楼 shingoscar 的回复:] base64里有加号,到服务器上就变空格了,自己用负号或下划线之类的替换下就行了
对比出问题的地方确实是+号变成了空格,你有没有成熟的替换用例呢。[/quote] value = value.Replace("+", "-"); resStr = resStr.Replace("-", "+"); 替换下也不会么。。。
枫0子K 2017-02-18
  • 打赏
  • 举报
回复
引用 3 楼 Forty2 的回复:
为什么你不直接用application/octet-stream? 同base64比,传输量可以少四分之一,还不用麻烦转来转去。 client.UploadData(url, comData);
求指教,对网络传输这块钻研还不深,麻烦写一点代码段方便理解,然后是否有资料支持你说的传输量少4分之一的说法也请贴出来大家学习学习,感谢!
枫0子K 2017-02-18
  • 打赏
  • 举报
回复
引用 2 楼 shingoscar 的回复:
base64里有加号,到服务器上就变空格了,自己用负号或下划线之类的替换下就行了
对比出问题的地方确实是+号变成了空格,你有没有成熟的替换用例呢。
Forty2 2017-02-18
  • 打赏
  • 举报
回复
为什么你不直接用application/octet-stream? 同base64比,传输量可以少四分之一,还不用麻烦转来转去。 client.UploadData(url, comData);
Poopaye 2017-02-18
  • 打赏
  • 举报
回复
base64里有加号,到服务器上就变空格了,自己用负号或下划线之类的替换下就行了
枫0子K 2017-02-18
  • 打赏
  • 举报
回复
顶一个,好像是猜到了分布式的坑?

110,502

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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