Delphi socket连接.net Socket

页面导航:首页 > 软件编程 > Delphi > Delphi socket连接.net Socket

Delphi socket连接.net Socket

来源: 作者: 时间:2016-01-18 15:42 【

[csharp]这几天一直研究Delphi连接.net的socket程序,终于有一些进展。需求:服务端截取前4个字节,转换为数字,次数字为业务代码。将决定调用哪个业务逻辑。[html] using System; using System
[csharp] 
  
这几天一直研究Delphi连接.net的socket程序,终于有一些进展。
需求:
服务端截取前4个字节,转换为数字,次数字为业务代码。将决定调用哪个业务逻辑。
[html]  
using System;  
using System.Collections.Generic;  
using System.Text;  
using System.IO;  
using System.Net.Sockets;  
using System.Threading;  
using PivasUpdate;  
using log4net;  
using System.Reflection;  
using System.Net;  
  
namespace PivasUpdate  
{  
  
    public class ServiceProcess  
    {  
        private const int LENGTH=1024;  
  
        private const int GETVERSION = 1;  
        private const int DOWNLOADNEW = 2;  
        private const int DOWNLOADFILE = 3;  
  
        public static AutoResetEvent allDone = new AutoResetEvent(false);  
        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);  
        private string cliendAddres;  
        private string INSTALLPATH = ConfigUtils.GetWindowsServiceInstallPath(ConfigUtils.SERVICENAME);  
  
        public void ProcessCallback(IAsyncResult ar)  
        {  
            Socket handler = null;  
            try  
            {  
  
                StateObject state = (StateObject)ar.AsyncState;  
                handler = state.workSocket;  
                cliendAddres = IPAddress.Parse(((IPEndPoint)handler.RemoteEndPoint).Address.ToString()) + ":"  
                + ((IPEndPoint)handler.RemoteEndPoint).Port.ToString() + ":";  
  
                int bytesRead = handler.EndReceive(ar);  
                log.Info(cliendAddres + "接受到数据包大小:" + bytesRead + "字节");  
  
  
                int control = BitConverter.ToInt32(state.buffer, 0);  
  
                string c = UTF8Encoding.UTF8.GetString(state.buffer, 4, bytesRead - 4);  
  
                switch (control)  
                {  
                    case GETVERSION:  
                        log.Info(cliendAddres + "获取最新版本,请求版本号:" + c);  
                        GetVersionNo(c, handler);  
                        break;  
                    case DOWNLOADNEW:  
                        log.Info(cliendAddres + "更新配置文件:" + INSTALLPATH+"/"+c);  
                        DownLoadNew(c, handler);  
                        break;  
                    case DOWNLOADFILE:  
                        log.Info(cliendAddres + "下载文件," + INSTALLPATH+"/"+c);  
                        DownLoadFile(INSTALLPATH + "/" + c, handler);  
                        break;  
                    default:  
                        break;  
                }  
  
            }  
            catch (Exception e)  
            {  
                log.Error(cliendAddres + "程序出错," + e.Message);  
            }  
            finally  
            {  
                if (handler != null)  
                {  
                    handler.Shutdown(SocketShutdown.Both);  
                    handler.Close();  
                    handler = null;  
                    log.Info("与客户端:" + cliendAddres + "断开连接。");  
                }  
            }  
             
        }  
  
        public void DownLoadFile(string filePath,Socket handler)  
        {  
            if (!File.Exists(filePath))  
            {  
                string fail = "文件不存在.";  
                log.Info(cliendAddres+"访问文件:"+filePath+"不存在。");  
                byte[] failBytes = Encoding.UTF8.GetBytes(fail);  
                handler.BeginSend(failBytes, 0, failBytes.Length, 0, new AsyncCallback(SendCallBack), handler);  
                allDone.WaitOne();  
                return;  
            }  
  
            handler.BeginSendFile(filePath, new AsyncCallback(delegate(IAsyncResult ar)  
                {  
                    handler.EndSendFile(ar);  
                    allDone.Set();  
                    log.Info(cliendAddres+"发送文件:"+filePath+"成功.");  
                }  
                ), handler);  
            allDone.WaitOne();  
  
  
        }  
  
  
        public void DownLoadNew(string versioncode,Socket handler)  
        {  
            string[] strs = versioncode.Split('.');  
            string result = "";  
            List<byte> resbyte = new List<byte>();  
  
            if (strs.Length != 3)  
            {  
                result = "版本号错误";  
                log.Warn(cliendAddres+"版本号错误," + versioncode);  
                resbyte.AddRange(Encoding.UTF8.GetBytes(result));  
                handler.BeginSend(resbyte.ToArray(), 0, resbyte.Count, 0, new AsyncCallback(SendCallBack), handler);  
                return;  
            }  
  
            FileStream stream = File.OpenRead(INSTALLPATH+"/version/" + versioncode + "/update.xml");  
            List<byte> list = new List<byte>();  
            int count = 0;  
  
            byte[] buf = new byte[1024];  
            while ((count=stream.Read(buf,0,buf.Length))>0) list.AddRange(buf);  
  
            handler.BeginSendFile(INSTALLPATH+"/version/" + versioncode + "/update.xml", new AsyncCallback(delegate(IAsyncResult ar)  
                {  
                    handler.EndSendFile(ar);  
                    log.Info(cliendAddres+"发送文件成功,文件名update.xml");  
                    allDone.Set();  
                }  
                ), handler);  
            allDone.WaitOne();  
        }  
  
        public void GetVersionNo(string content,Socket handler)  
        {  
            string[] strs = content.Split('.');  
            string result = "";  
            List<byte> resbyte = new List<byte>();  
  
            if (strs.Length != 3)  
            {  
                result = "版本号错误";  
                log.Warn(cliendAddres+"版本号错误,"+content);  
                resbyte.AddRange(Encoding.UTF8.GetBytes(result));  
                handler.BeginSend(resbyte.ToArray(), 0, resbyte.Count, 0, new AsyncCallback(SendCallBack), handler);  
                return;  
            }  
  
            string[] dirs = Directory.GetDirectories(INSTALLPATH+"/version");  
            for (int i = 0; i < dirs.Length; i++)  
            {  
                if (dirs[i].EndsWith("\\"+content))  
                {  
                    if (i != dirs.Length - 1)  
                    {  
                        result = Directory.CreateDirectory(dirs[i + 1]).Name;  
                        break;  
                    }  
                    else  
                    {  
                        result = dirs[i];  
                    }  
                }  
            }  
  
            if (result == "")  
            {  
                resbyte.AddRange(Encoding.UTF8.GetBytes("没有找到此版本。"));  
                log.Warn(cliendAddres+"没有找到版本:"+content);  
            }  
            else  
            {  
                resbyte.AddRange(Encoding.UTF8.GetBytes(result));  
                log.Info(cliendAddres+"发送新版本号:"+result);  
            }  
            handler.BeginSend(resbyte.ToArray(), 0, resbyte.Count, 0, new AsyncCallback(SendCallBack), handler);  
            allDone.WaitOne();  
        }  
  
  
        private void SendCallBack(IAsyncResult ar)  
        {  
            try  
            {  
                // Retrieve the socket from the state object.  
                Socket handler = (Socket)ar.AsyncState;  
  
                // Complete sending the data to the remote device.  
                int bytesSent = handler.EndSend(ar);  
                log.Info(cliendAddres+"发送成功,发送字节数:"+bytesSent);  
                allDone.Set();  
  
            }  
            catch (Exception e)  
            {  
                log.Error(cliendAddres+"发送失败:"+e.Message,e);  
            }  
        }  
  
         
    }  
}  
 
以上代码为服务端逻辑。
 
使用TclientSocket连接服务端程序。
 
其中有几大问题。
TclientSocket.sendBuf可以发送任意字符字节等数据,但是我们这块的想法是前4个字节为数字,后面为自定义的字符串,因此这就需要将字节进行处理。
首先将数字转换为4个字节数组,然后将字符串转换为utf8编码的字节数组然后进行组合,发送。意想不到的是程序发送成功后,没有任何返回的结果。
然后在服务端进行代码的跟踪,发现服务端接受的字节数组顺序已乱,转换的数字已经出错。因此不会返回任何的结果。
 
后来经过多方面原因的查找,发现在delphi中字节数组使用的是动态数组 array of byte ,delphi动态数组在经过socket缓冲区时,会出现数据混乱的现象,那如何解决呢?
经多面证实发现,使用静态数组 array [1..5] of byte 可以发送成功,服务端也可以解码成功。
 
但是如果数据是动态的,长度也不确定,那么这种方式也是不适用的。所以程序还是需要改进的,可以这么做所有的指令还有数据都是字符串,服务端首先解码,转换为字符串,然后在解析字符串的指令。
经过研究sendBuf的方法发现第一个参数需要的是一个指针类型,而我传递的是一个数组,按道理来说两个的效果都是一样的,都是数组的第一个元素的地址,但是情况明显不是这样的。直接将数组当作参数返回的数数组对象的地址,而将第一个数组元素作为参数传递,则会将第一个元素的地址传递。因此将参数换掉就ok。
 
下面看一下delphi使用静态数组如何发送指令
[delphi]  
var  
 arr2 : TBytes;  
 arr1 : array [0..14] of byte;  
 seendText : UTF8String;  
 rectext : WideString;  
begin  
  mmo.Lines.Add('发送指令'+inttostr(1));  
  with client do  
  begin  
    Open;  
    //SetLength(arr1,4);  
    arr1[0]:=1;  
    seendText:= UTF8Encode('1.1302.1714');  
    //SetLength(arr1,Length(arr1)+Length(seendText));  
    Move(seendText[1],arr1[4],Length(seendText));  
    client.Socket.SendBuf(arr1,Length(arr1));  
    rectext:=UTF8Decode(client.Socket.ReceiveText);  
    mmo.Lines.Add(rectext);  
    Close;  
  end;  
end;  
 
Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<