.net Socket 网络编程(五)

来源:互联网 发布:备份应用的软件 编辑:程序博客网 时间:2024/05/22 12:16

在(四)中已经实现了简单的客户端,服务器端的异步数据传输。
现在让我们继续完善功能实现文件的上传 

客户端部分
修改文件流,在头部添加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, 08, 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();
        }