我用的是delphi5 oracle 8.1.6 。
我想做一个接口程序,实现对自己数据库的数据进行录入,查询和修改,统计。
数据是有pda发到对方一个服务器,对方服务器再把数据通过clientsocket转发到我做的接口程序(serversocket)里(pda对方发一个请求,对方服务器将自动产生一个线程,向我的接口程序里面发送数据,最多是40个),然后我通过Ado连接数据库,在对数据进行处理,并把结果返回去。对方服务器是用c做的,可以对内存直接操作,功能实现容易一些。我这用delphi5来做,好多功能没有c语言功能强大。现在单条的都没有问题,可以实现。对于多条的并发,当第一条我还没处理完时,后面的又发过来的时候,我这将会出现掉包的现象。我不太清楚怎么处理。而且我对线程不太熟悉,希望你能给一些帮助。
最好能给提供一些源代码。
信箱:[email protected]谢谢!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

解决方案 »

  1.   

    改变socket的设置,里面有个属性,就是可以同时发送多条信息的,
    你自己多看一看,我记不清是那个了,但是有个问题就是,这样会导致很慢的,
    注意98系统,很容易出问题,也许你编的程序,在2000 server下
    没问题,但是在98下可就出现了,例如响应回复信息需要很长时间的问题,
    还有突然死机的问题,等等,所以一定注意客户用的系统,为什么不用
    com\dcom\com+编写,我个人认为,用com\dcom\com+没有那么多问题,
    而且实现你的要求很容易,用socket有很多你想多想不到的问题出现,
    而且出了问题你连问的地方多没有,这样的程序我多编写过,我感觉最
    困难的还是socket编程,因为它是最底层的。
      

  2.   

    Working with Blocking Sockets and Threads
    A program like the one I’ve just built is nice, but it won’t really scale up on a large system,
    because the server uses a blocking connection and the requests are processed in sequence.
    Now, even if making the database-related code multithreading wouldn’t be easy, I’ll take the
    excuse of this example to show you how to build a program based on blocking sockets and
    threads. (If you don’t know much about threads, read the sidebar “Working with Threads”
    before proceeding.)
    Working with Threads
    Win32 has an API to allow two procedures or methods execute at the same time. Delphi provides
    a TThread class that will let us create and control threads. The first thing to know about
    the TThread class is that you never use it directly, because it is an abstract class—a class with a
    virtual abstract method. To use threads, you always subclass TThread (optionally starting with
    the Thread Object of the New Items dialog box (File ➢ New ➢ Other) and use the features of
    this base class.
    The TThread class has a constructor with a single parameter (CreateSuspended) that lets you
    choose whether to start the thread immediately or suspend it until later. There are also some
    public synchronization methods:
    procedure Resume;
    procedure Suspend;
    function Terminate: Integer;
    function WaitFor: Integer;
    The published properties include Priority, Suspended, and two read-only, low-level values:
    Handle and ThreadID. The class also provides a protected interface, which includes two key
    methods for your thread subclasses:
    procedure Execute; virtual; abstract;
    procedure Synchronize(Method: TThreadMethod);
    The Execute method, declared as a virtual abstract procedure, must be redefined by each
    thread class. It contains the main code of the thread, the code you would typically place in
    a thread function when using the Windows API.
    The Synchronize method is used to avoid concurrent access to VCL components. The VCL
    code runs inside the main thread of the program, and you need to synchronize access to VCL to
    avoid reentry problems (errors from reentering a function before a previous call is completed)
    and concurrent access to shared resources. The only parameter of Synchronize is a method
    that accepts no parameters, typically a method of the same thread class. As you cannot pass
    parameters to this method, it is common to save some values within the data of the thread
    object in the Execute method and use those values in the synchronized methods.Another way to avoid conflicts is to use the synchronization techniques offered by the operating
    system. The SyncObjs unit defines VCL classes for some of these low-level synchronization
    objects: events (with the TEvent class and the TSingleEvent class) and critical sections (with
    the TCriticalSection class).
    In the server program (see the SockDbThread example on the companion CD), the socket
    component now has a thread-blocking type and has handlers for many events, including in
    particular OnGetThread. No methods are hooked to the read and write events, as they won’t
    be triggered anymore (they are used exclusively by message-based nonblocking sockets):
    object ServerSocket1: TServerSocket
    Active = True
    Port = 51
    ServerType = stThreadBlocking
    OnAccept = ServerSocket1Accept
    OnGetThread = ServerSocket1GetThread
    OnClientConnect = ServerSocket1ClientConnect
    OnClientDisconnect = ServerSocket1ClientDisconnect
    end
    The OnAccept, OnClientConnect, and OnClientDisconnect event handlers are used only
    for logging information to the screen, while the OnGetThread event handler has a key role of
    creating the server-side thread object:
    procedure TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket:
    TServerClientWinSocket; var SocketThread: TServerClientThread);
    begin
    lbLog.Items.Add( ‘GetThread: ‘ + ClientSocket.RemoteHost + ‘ (‘ +
    ClientSocket.RemoteAddress + ‘)’ );
    SocketThread := TDbServerThread.Create(False, ClientSocket);
    end;
    This must be an object of a class inherited by the specific TServerClientThread class
    (not the generic Delphi TThread class) and with its core code placed in an overridden
    ClientExecute method (not the generic Execute method):
    type
    TDbServerThread = class(TServerClientThread)
    private
    strCommand: string;
    strFeedback: string;
    public
    procedure ClientExecute; override;
    procedure Log;
    procedure LogFeedback;
    procedure AddRecord;
    end;
    procedure TDbServerThread.ClientExecute;
    var
    Stream: TWinSocketStream;
    Buffer, strIn: string;
    nRead: Integer;
    begin
    // keep going
    Stream := TWinSocketStream.Create(ClientSocket, 5000);
    try
    while not Terminated and ClientSocket.Connected do
    begin
    // initialize (thread might be reused)
    Buffer := ‘’;
    strIn := ‘’;
    SetLength(Buffer, 64);
    repeat
    nRead := Stream.Read(Buffer[1], 64);
    if nRead = 0 then
    begin
    ClientSocket.Close;
    Break;
    end;
    SetLength (Buffer, nRead);
    StrIn := StrIn + Buffer;
    until (Pos(#10#13 ’.’#10#13, Buffer) > 0);
    if strIn = ‘’ then
    Continue // keep going
    else
    begin
    // handle the request, if anything arrived
    StrCommand := Copy (strIn, 1, Pos (#10#13 ’.’#10#13, strIn) -1);
    Synchronize(Log);
    Synchronize(AddRecord);
    // send results back
    Synchronize(LogFeedback);
    Stream.Write(strFeedback[1], Length (strFeedback));
    end;
    end;
    finally
    Stream.Free;
    end;
    end;
    The server reads data from the client and sends the feedback using a TWinSocketStream, a
    compulsory approach for blocking servers. The thread is kept active, as it can be reused for
    subsequent calls, and reads from a buffer until it find a specific separator (in this case, a dot
    between two line separators, exactly as occurs in the SMTP protocol). When the data is
    received, the server does a synchronized call to the AddRecord method, which is similar to the
    code of the previous version of the example.
    WARNING This approach is far from perfect, as all database accesses are serialized, but you could solve
    the problem by moving the database access component within the thread and adding a Session
    object in case of a BDE application. Not all databases like multithreaded access, though,
    so serializing the calls is not always a bad idea.
    This is the multithreaded server application. The client program, instead, uses a standard
    thread class, derived from TThread. The class creates a client server object internally, so that
    multiple threads could spawn multiple socket connections in parallel (something the program
    doesn’t really use) and receives a table to work on as parameter in the constructor:
    type
    TLogEvent = procedure(Sender: TObject; LogMsg: String) of object;
    TSendThread = class(TThread)
    private
    ClientSocket: TClientSocket;
    FTable: TTable;
    FOnLog: TLogEvent;
    FLogMsg: String;
    procedure SetOnLog(const Value: TLogEvent);
    protected
    procedure Execute; override;
    procedure DoLog;
    public
    constructor Create(ATable: TTable);
    property OnLog: TLogEvent read FOnLog write SetOnLog;
    end;
    On the client side, the finite-state machine logic (send, set the wait flag, receive another
    event, disable the flag, get the next record) is now replaced by a continual and more logical
    flow of operations, all part of the Execute method of the thread. You need to add some code
    to let the program wait until the server sends a reply. Again, the blocking socket of the client
    is not used directly but via a TWinSocketStream object:
      

  3.   


    procedure TSendThread.Execute;
    var
    I: Integer;
    Data: TStringList;
    Stream: TWinSocketStream;
    Buf: String;
    begin
    try
    Data := TStringList.Create;
    ClientSocket := TClientSocket.Create (nil);
    Stream := nil;
    try
    ClientSocket.Address := EditServer.Text;
    ClientSocket.ClientType := ctBlocking;
    ClientSocket.Port := 51;
    ClientSocket.Active := True;
    Stream := TWinSocketStream.Create(ClientSocket.Socket, 30000);
    FTable.First;
    while not FTable.Eof do
    begin
    // if the record is still not logged
    if FTable.FieldByName( ‘CompID’).IsNull or
    (FTable.FieldByName( ‘CompID’).AsInteger = 0) then
    begin
    FLogMsg := ‘Sending ‘ + Table.FieldByName( ‘Company’).AsString;
    Synchronize(DoLog);
    Data.Clear;
    // create strings with structure “FieldName=Value”
    for I := 0 to FTable.FieldCount - 1 do
    Data.Values [FTable.Fields[I].FieldName] :=
    FTable.Fields [I].AsString;
    // send the record followed by separator
    Buf := Data.Text + #10#13 ’.’#10#13;
    ClientSocket.Socket.SendText(Buf);
    // wait for reponse
    if Stream.WaitForData(30000) then
    begin
    FTable.Edit;
    SetLength(Buf, 256);
    SetLength(Buf, Stream.Read(Buf[1], Length(Buf)));
    FTable.FieldByName( ‘CompID’).AsString := Buf;
    FTable.Post;
    FLogMsg := FTable.FieldByName( ‘Company’).AsString +
    ‘ logged as ‘ + FTable.FieldByName( ‘CompID’).AsString;
    end
    else
    FlogMsg := ‘No response for ‘ +
    FTable.FieldByName(‘Company’).AsString;
    Synchronize(DoLog);
    end;
    FTable.Next;
    end;
    finally
    ClientSocket.Active := False;
    ClientSocket.Free;
    Stream.Free;
    Data.Free;
    end;
    except
    // trap exceptions
    end;
    end;
    The thread also has an event handler to let the forms using it define the effect of the OnLog
    operation, in the synchronized DoLog method. Finally, this is how the thread starts, when the
    user clicks a button in the form:
    procedure TForm1.Button2Click(Sender: TObject);
    var
    SendThread: TSendThread;
    begin
    SendThread := TSendThread.Create(Table1);
    SendThread.OnLog := OnLog;
    SendThread.Resume;
    end;
      

  4.   

    以上是关于用阻塞套接字和线程工作的描述但愿对楼主有用。以上内容摘自《mastering delphi6》