在(四)中已经实现了简单的客户端,服务器端的异步数据传输。
现在让我们继续完善功能实现文件的上传
客户端部分
修改文件流,在头部添加8个字节位置保存实际文件字节长度
修改AsyncConnect方法
//
开始异步连接
public
void
AsyncConnect()

...
{
try

...{
InitIPInfo();

Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallback), serverSocket);
connectDone.WaitOne(); //阻止运行直到连接成功

//发送数据
FileStream fs = new FileStream(_file, FileMode.Open);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, (int)fs.Length);
long fileLen = fs.Length;
byte[] bufferFile = BitConverter.GetBytes(fileLen);
buffer = ComBineArray<byte>(bufferFile, buffer);
Console.WriteLine("共有很数据 {0} bytes 需要发送,其中文件大小 {1} bytes",buffer.Length,bufferFile.Length);
serverSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), serverSocket);
sendDone.WaitOne();


StateObject state = new StateObject();
state.workSocket = serverSocket;
serverSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
receiveDone.WaitOne();
Console.WriteLine("接收到服务器信息:{0}", response);

serverSocket.Shutdown(SocketShutdown.Both);
serverSocket.Close();
}
catch(Exception ex)

...{
Console.WriteLine("发生异常"+ex.Message);
}

}
这是用来联合两个byte数组的方法
private
static
T[] ComBineArray
<
T
>
(T[] a1, T[] a2)

...
{
T[] result = new T[a1.Length + a2.Length];
int a1Len = Buffer.ByteLength(a1);
int a2Len = Buffer.ByteLength(a2);

Buffer.BlockCopy(a1, 0, result, 0, a1Len);
Buffer.BlockCopy(a2, 0, result, a1Len, a2Len);
return result;
}
服务器部分
在异步acceptCallback方法中修改第一次读取的字节数
private
void
acceptCallback(IAsyncResult ar)

...
{
Console.WriteLine("acceptCallback 被调用");
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar); //获得客户端套接字接口
Console.WriteLine("建立连接");
allDone.Set();

StateObject state = new StateObject();
state.WorkSocket = clientSocket;
// 第一次调用先取8个字节
clientSocket.BeginReceive(state.buffer, 0, 8, SocketFlags.None, new AsyncCallback(readCallback), state); //开始接受数据

}
修改readCallback方法
public
void
readCallback(IAsyncResult ar)

...
{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.WorkSocket;

try

...{
int read = 0;
read = clientSocket.EndReceive(ar);//结束挂起的异步读取
Console.WriteLine("获得字节{0}bytes",read);
if (read > 0)

...{
if (read == 8 && totalBytes == 0) //获得文件长度标识

...{
totalBytes += read;
fileBytes = BitConverter.ToInt64(state.buffer, 0);
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
}
else

...{
totalBytes += read;
if (read != StateObject.BufferSize)

...{
byte[] resultBytes = new byte[read];
Buffer.BlockCopy(state.buffer, 0, resultBytes, 0, (int)read);
state.totalBuffer = ComBineArray<byte>(state.totalBuffer, resultBytes);
}
else

...{
state.totalBuffer = ComBineArray<byte>(state.totalBuffer, state.buffer);
}

if (totalBytes == fileBytes + 8)

...{
Console.WriteLine("已经接收完数据,共{0}bytes,最后一批{1}bytes",state.totalBuffer.Length,state.buffer.Length);
//保存文件
CreateFile(state.totalBuffer);
//回复客户端
byte[] backBuffer = new byte[1024];
string backString = "文件上传完成";

backBuffer = Encoding.GetEncoding("gb2312").GetBytes(backString);
clientSocket.BeginSend(backBuffer, 0, backBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), state);
}
else

...{
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
}
}
}
}
catch (SocketException se)

...{
if (se.ErrorCode == 10054)

...{
Console.WriteLine("客户端已断开连接!");
}
else

...{
Console.WriteLine(se.Message);
}
}
catch (Exception ex)

...{
Console.WriteLine(ex.Message);
}
}
创建新文件方法
private
void
CreateFile(
byte
[] bytes)

...
{
string fileName = "aaOnServer.txt";
string filePath = Path.Combine(Application.StartupPath, fileName);

FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();
fs.Close();
}