我编写了一个使用servicestack的服务器,以及一个使用JSON和protobuf-net连接到它的客户端(所以我确定服务器正常工作......)。 现在我需要在Windows Mobile上使用CF3.5开发相同的客户端,并且由于CF3.5不支持servicestack,我在客户端HttpWebRequest和NewtonSoft.Json.Compact上使用json部分,这样:
类:
[ProtoContract]
public class ReqPing
{
}
[ProtoContract]
public class RespPing
{
[ProtoMember(1)]
public string Result { get; set; }
}
功能:
ReqPing iReqPing = new ReqPing();
string json = JsonConvert.SerializeObject(iReqPing);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/json/syncreply/ReqPing");
req.ContentType = "text/json";
req.Method = "POST";
req.ContentLength = json.Length;
using (var streamWriter = new StreamWriter(req.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream respStream = resp.GetResponseStream();
string resps;
using (var reader = new StreamReader(respStream, Encoding.UTF8))
{
resps = reader.ReadToEnd();
}
respStream.Close();
JsonTextReader jreader = new JsonTextReader(new StringReader(resps));
JsonSerializer serializer = new JsonSerializer();
RespPing iRespPing = serializer.Deserialize<RespPing>(jreader);
并且它有效,所以现在我正在尝试用protobuf实现相同的功能,而且我被困在这里:
ReqPing iReqPing = new ReqPing();
var ms = new MemoryStream();?????? correct way?
Serializer.Serialize<ReqPing>(ms, iReqPing);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/x-protobuf/reply/ReqPing");
req.ContentType = "application/x-protobuf";
req.Method = "POST";
req.ContentLength = ????????
how can I write the serialized stream to req??
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream respStream = resp.GetResponseStream();
RespPing iRespPing = Serializer.Deserialize<RespPing>(respStream);
任何人都可以建议我采用什么方法?
谢谢! 马蒂亚
编辑:
确定如何使用流,但我也需要设置ContentLength,或者我在GetRequestStream上收到错误消息(说我必须设置ContentLength ...)。 我使用了它:
byte[] data;
using(var stream = new MemoryStream())
{
Serializer.Serialize(stream, iReqPing);
data = stream.ToArray();
req.ContentLength = data.Length;
}
using(var stream = req.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
我还有另一种明显缺失的方法吗?
另一个问题: 我让它工作但是在两个请求之后,在第三个它在GetRequestStream中超时。我注意到我在之前的调用中忘了在我的HttpWebResponse中调用Close(),我纠正了它,现在有效了。 奇怪的是,即使使用我的JSON版本,我忘了关闭HttpWebResponse,并且我没有问题......例行程序完全一样..你能猜出原因吗? 再次感谢!
答案 0 :(得分:1)
如何将序列化流写入req ??
using(var stream = req.GetRequestStream()) {
Serializer.Serialize(stream, iReqPing);
}
然后反序列化,正如您已经正确使用的那样:
RespPing iRespPing;
using(var stream = resp.GetResponseStream()) {
iRespPing = Serializer.Deserialize<RespPing>(respStream);
}
除非您特别想手动发送长度,否则无需MemoryStream
。如果您做想要缓冲,那么可能:
byte[] data;
using(var stream = new MemoryStream()) {
Serializer.Serialize(stream, iReqPing);
data = stream.ToArray();
}
...
using(var stream = req.GetRequestStream()) {
stream.Write(data, 0, data.Length);
}
修改以更有效地使用MemoryStream
现在编辑过的问题:
byte[] data;
int len;
using(var stream = new MemoryStream())
{
Serializer.Serialize(stream, iReqPing);
data = stream.GetBuffer(); // note this is oversized!
len = (int)stream.Length;
}
req.ContentLength = len;
using(var stream = req.GetRequestStream())
{
stream.Write(data, 0, len);
}
这里的细微之处在于我们避免了必须复制MemoryStream
的缓冲区 - 而是获得了超大后台缓冲区(记得注意到它有多少是实际数据) ),然后写只是那么多字节。因此data.Length
可以(例如)4096
,但len
可以是3012
。这样可以避免额外的byte[]
分配和Buffer.BlockCopy
。