我希望实现的功能是服务器把消息、播放列表和列表中所列的图片和视频都发给客户端。在写发送文件的时候遇到了几个问题。
1.传送xml文件时,传给客户端,打开后总是有这样一条提示【字符''(十六进制值0x0)在xml文档中是非法的】。
2.传送的图片和视频,在客户端都无法打开,奇怪的是我收到的包总是比发的要多。server发送:FileStream fsimg = new FileStream(System.Windows.Forms.Application.StartupPath + "\\MediaLists.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
string strHead = "P" + ((char)191).ToString() + "MediaLists.xml" + ((char)191).ToString();
int bigsize = 10000;
long fsleng = fsimg.Length;
double bnum = fsleng / bigsize;
bnum = Math.Floor(bnum + 1);
strHead += bnum.ToString() + ((char)191).ToString();
int bytes = 0;
int bytes_num = 0;
byte[] bytedata = new byte[bigsize];
Socket s = (Socket)slist[i];
Send(s, strHead);
while (bytes_num < fsleng)
{
bytes = fs.Read(bytedata, 0, bigsize);
string strsend = Encoding.UTF8.GetString(bytedata);
strsend = strsend.Replace("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "*");
bytedata = Encoding.UTF8.GetBytes(strsend);
Send(s, bytedata);
bytes_num += bytes;
}
Send(s, ((char)191).ToString() + "O");client接收:private void ReadCallback(IAsyncResult ai)
{
try
{
StateObject state = (StateObject)ai.AsyncState;
Socket client = state.workSocket;
int byteread = client.EndReceive(ai);
if (byteread > 0)
{
state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, byteread));
listbyte.Add(state.buffer);
} switch (state.sb.ToString().Substring(0, 1))
{
case "P":
//对文件的处理
string s = state.sb.ToString();
string strOver = s.Substring(s.Length - 1);
string[] strRecr = state.sb.ToString().Split((char)191);
string strFileName = strRecr[1].ToString();
int intNum = Convert.ToInt32(strRecr[2].ToString());
if (strOver == "O")
{
FileStream fsRecv = File.Create(System.Windows.Forms.Application.StartupPath + "\\" + strFileName);
for (int i = 1; i < listbyte.Count-1; i++)
{
byte[] byteB = (byte[])listbyte[i];
fsRecv.Write(byteB,0,byteB.Length);
}
fsRecv.Close();
listbyte.Clear();
state.sb.Remove(0, state.sb.Length);
}
break;
case "M":
//对消息的处理
state.sb.Remove(0, state.sb.Length);
listbyte.Clear();
break;
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch () { };
}
}
1.传送xml文件时,传给客户端,打开后总是有这样一条提示【字符''(十六进制值0x0)在xml文档中是非法的】。
2.传送的图片和视频,在客户端都无法打开,奇怪的是我收到的包总是比发的要多。server发送:FileStream fsimg = new FileStream(System.Windows.Forms.Application.StartupPath + "\\MediaLists.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
string strHead = "P" + ((char)191).ToString() + "MediaLists.xml" + ((char)191).ToString();
int bigsize = 10000;
long fsleng = fsimg.Length;
double bnum = fsleng / bigsize;
bnum = Math.Floor(bnum + 1);
strHead += bnum.ToString() + ((char)191).ToString();
int bytes = 0;
int bytes_num = 0;
byte[] bytedata = new byte[bigsize];
Socket s = (Socket)slist[i];
Send(s, strHead);
while (bytes_num < fsleng)
{
bytes = fs.Read(bytedata, 0, bigsize);
string strsend = Encoding.UTF8.GetString(bytedata);
strsend = strsend.Replace("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "*");
bytedata = Encoding.UTF8.GetBytes(strsend);
Send(s, bytedata);
bytes_num += bytes;
}
Send(s, ((char)191).ToString() + "O");client接收:private void ReadCallback(IAsyncResult ai)
{
try
{
StateObject state = (StateObject)ai.AsyncState;
Socket client = state.workSocket;
int byteread = client.EndReceive(ai);
if (byteread > 0)
{
state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, byteread));
listbyte.Add(state.buffer);
} switch (state.sb.ToString().Substring(0, 1))
{
case "P":
//对文件的处理
string s = state.sb.ToString();
string strOver = s.Substring(s.Length - 1);
string[] strRecr = state.sb.ToString().Split((char)191);
string strFileName = strRecr[1].ToString();
int intNum = Convert.ToInt32(strRecr[2].ToString());
if (strOver == "O")
{
FileStream fsRecv = File.Create(System.Windows.Forms.Application.StartupPath + "\\" + strFileName);
for (int i = 1; i < listbyte.Count-1; i++)
{
byte[] byteB = (byte[])listbyte[i];
fsRecv.Write(byteB,0,byteB.Length);
}
fsRecv.Close();
listbyte.Clear();
state.sb.Remove(0, state.sb.Length);
}
break;
case "M":
//对消息的处理
state.sb.Remove(0, state.sb.Length);
listbyte.Clear();
break;
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch () { };
}
}
{
NetworkStream _Ns; const int Block = 500 * 1024; public delegate void SendFileProgressChangedCallback(object sender, ProgressChangedEventArgs e);
public delegate void ReceiveFileProgressChangedCallback(object sender, ProgressChangedEventArgs e);
public event SendFileProgressChangedCallback SendFileProgressChanged;
public event ReceiveFileProgressChangedCallback ReceiveFileProgressChanged; public TcpSendReceive(NetworkStream ns)
{
_Ns = ns;
} public bool SendInt(int value)
{
byte[] buffer= BitConverter.GetBytes(value);
_Ns.Write(buffer, 0, buffer.Length);
return true;
} public int ReceiveInt()
{
byte[] buffer = new byte[4];
_Ns.Read(buffer, 0, 4);
return BitConverter.ToInt32(buffer, 0);
} public bool SendLong(long value)
{
byte[] buffer =BitConverter.GetBytes(value);
_Ns.Write(buffer, 0, buffer.Length);
return true;
} public long ReceiveLong()
{
byte[] buffer = new byte[8];
_Ns.Read(buffer, 0, 8);
return BitConverter.ToInt64(buffer, 0);
} public bool SendString(string str)
{
byte[] buffer = Encoding.UTF8.GetBytes(str);
byte[] resultBuffer = new byte[8 + buffer.Length];
BitConverter.GetBytes(buffer.Length).CopyTo(resultBuffer, 0);
buffer.CopyTo(resultBuffer, 8);
_Ns.Write(resultBuffer, 0, resultBuffer.Length);
return true;
} public string ReceiveString()
{
long length = ReceiveLong();
int current;
if (length > Block)
{
current = Block;
}
else
{
current =(int)length;
} byte[] buffer=new byte[current]; int read = _Ns.Read(buffer, 0, current); long receive = read; byte[] resultBuffer = new byte[length];
buffer.CopyTo(resultBuffer, 0); while (read > 0 && length > receive)
{
if ((length - receive) > Block)
{
current = Block;
}
else
{
current =(int)( length - receive);
} buffer = new byte[current]; read = _Ns.Read(buffer, 0, current); receive += read; buffer.CopyTo(resultBuffer, 0);
} return Encoding.UTF8.GetString(resultBuffer);
} public bool SendFile(string filePath)
{
byte[] length = new byte[8]; FileInfo fi=new FileInfo(filePath);
BitConverter.GetBytes(fi.Length).CopyTo(length, 0);
_Ns.Write(length, 0, 8); int read;
byte[] buffer = new byte[Block]; ProgressChangedEventArgs e=new ProgressChangedEventArgs();
e.Length = fi.Length; using (FileStream fs = File.Open(filePath, FileMode.Open))
{
while ((read = fs.Read(buffer, 0, Block)) > 0)
{
_Ns.Write(buffer, 0, read);
e.Current += read; if (SendFileProgressChanged != null)
{
SendFileProgressChanged(this, e);
}
}
}
return true;
} public bool ReceiveFile(string filePath)
{
long length = ReceiveLong(); long receive;
if (File.Exists(filePath))
{
File.Delete(filePath);
}
string path = new FileInfo(filePath).Directory.FullName;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
} using (FileStream fs = File.Open(filePath, FileMode.OpenOrCreate))
{
int current;
byte[] buffer = new byte[Block];
if (length > Block)
{
current = Block;
}
else
{
current = (int)length;
} int read = _Ns.Read(buffer, 0, Block);
receive = read;
fs.Write(buffer, 0, read); ProgressChangedEventArgs e = new ProgressChangedEventArgs();
e.Length = length;
e.Current = receive; if (ReceiveFileProgressChanged != null)
{
ReceiveFileProgressChanged(this, e);
} while (read > 0 && length > receive)
{
if ((length - receive) > Block)
{
current = Block;
}
else
{
current = (int)(length - receive);
} read = _Ns.Read(buffer, 0, current);
receive += read;
fs.Write(buffer, 0, read); e.Current = receive; if (ReceiveFileProgressChanged != null)
{
ReceiveFileProgressChanged(this, e);
}
}
}
return true;
}
}//end class public class ProgressChangedEventArgs : EventArgs
{
long _Length;
long _Current; public long Length
{
get { return _Length; }
set { _Length = value; }
} public long Current
{
get { return _Current; }
set { _Current = value; }
}
}
string strsend = Encoding.UTF8.GetString(bytedata);
这里的fs我就找不到你的根据,不知道fs是什么,它读出的字节数怎么又受fsimg.Length的限制了呢?bytes完全可能比bigsize小,你怎么能不考虑这种情况而将整个bytedata转换为strsend?而bigsize只是“断章取义”地截取,有可能其最后的字节就切到unicode字符串中一个字符的中间,怎么能随便将bytedate就转成字符串了呢?哎呀,刚刚随便看了几行代码,每一行都至少有一两个明显逻辑错误,实在看不下去了。学好逻辑,学好结构和算法,写出的代码应该有清晰和可靠的基本章法,这样才好真正去工作。
FileStream fsimg = new FileStream(System.Windows.Forms.Application.StartupPath + "\\Vistalan.jpg", FileMode.Open, FileAccess.Read, FileShare.Read);
应该是:
FileStream fs = new FileStream(System.Windows.Forms.Application.StartupPath + "\\MediaLists.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
既然是xml文件,并且假设是utf8编码的文件,实际上你可以直接用一句
string strsend2=File.ReadAllText(path);读取出来。而要发送的内容整个组合到一个string中去,然后进需要一条send语句就可以发出。这样,你的发送端的代码至少可以减少一多半。做重要地是精简的代码往往更不同意出现逻辑错误。
如果你是使用tcp,在.net中使用TcpListener更好一些。当接收时,使用NetwrokStream的DataAvailable属性要比判断缓冲区的有效字符数更准确。有时候缓冲区没有接收到数据,但是DataAvailable可以正确地告诉你数据还有数据。
那么sb的最后一个字符恰好符合,可是并没有到最后一个真实“O”而是xml文件中或者图片中的“O”呢?至于你在解析中判断“M”,我猜你没有写下去。实际这又是考验你协议设计的另一个问题。视频内容可不是xml文件中的字符串。
string strHead = "";
int totalLength = (int)fs.Length; //文件总长度
int packetsSize = 64 * 1024; //包的大小
int packetsNum = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(fs.Length) / Convert.ToDouble(packetsSize))); //包的数量
int currentLength = 0; //当前包的大小
strHead = "P" + (char)191 + "ss.txt" + (char)191 + totalLength + (char)191 + packetsSize + (char)191 + packetsNum + (char)191 + (totalLength - (packetsNum - 1) * packetsSize).ToString();
byte[] byteH = System.Text.Encoding.Unicode.GetBytes(strHead.ToCharArray(0, strHead.Length));
string strF = "<over>";
byte[] byteF = System.Text.Encoding.Unicode.GetBytes(strF.ToCharArray(0, strF.Length));
byte[] byteBuffer = null;
for (int i = 0; i < slist.Count; i++)
{
Socket s = (Socket)slist[i];
Send(s, byteH);
for (int j = 0; j < packetsNum; j++)
{
if (totalLength > packetsSize)
{
currentLength = packetsSize;
totalLength -= currentLength;
}
else
{
currentLength = totalLength;
}
byteBuffer = new byte[currentLength];
count = fs.Read(byteBuffer, 0, currentLength);
byte[] SendingBuffer = new byte[currentLength];
SendingBuffer = byteBuffer;
Send(s, SendingBuffer);
}
Send(s, byteF);
}接受端:
收到结束标志后进行处理.
但现在的问题是虽然我会发送一个结束标志“Send(s, byteF); ”但这句根本得不到执行。