2011-12-07 20 views
17

thế nào có thể Indy của TIdTCPClientTIdTCPServer được sử dụng trong các tình huống sau:Indy TCP Client/Server với khách hàng đóng vai trò như một máy chủ

Client ---------- initate connection -----------> Server 
... 
Client <---------------command------------------- Server 
Client ----------------response-----------------> Server 
... 
Client <---------------command------------------- Server 
Client ----------------response-----------------> Server 

Client khởi kết nối, nhưng đóng vai trò như một "máy chủ" (chờ lệnh và thực hiện chúng).

Cách tiếp cận OnExecute của TIdTCPServer không hoạt động tốt trong trường hợp này (ít nhất tôi không làm cho nó hoạt động tốt). Làm thế nào tôi có thể làm điều này?

Tôi hy vọng câu hỏi này đủ rõ ràng.

+2

Có thể bạn có thể mô phỏng hành vi này bằng các phương thức 'IdTCPClient1.IOHandler.ReadLnWait' hoặc' IdTCPClient1.IOHandler.WaitFor'. Nếu không, bằng cách sử dụng 'TIdCmdTCPCLient' có thể giải quyết vấn đề của bạn. – LightBulb

+0

Phiên bản Indy nào? –

+0

Hiện tại, tôi đang sử dụng Indy 10 ở Delphi 2010. – LightBulb

Trả lời

17

Không có gì ngăn cản bạn thực hiện việc này với thành phần TIdTCPServer của Indy.

Máy chủ TIdTCPS chỉ thiết lập kết nối. Bạn sẽ cần phải thực hiện phần còn lại. Vì vậy, trình tự gửi và nhận thực tế có thể là bất cứ điều gì bạn muốn.

Đặt mã này trong trường hợp OnExecute phần TIdTCPServer của bạn:

var 
    sName: String; 
begin 
    // Send command to client immediately after connection 
    AContext.Connection.Socket.WriteLn('What is your name?'); 
    // Receive response from client 
    sName := AContext.Connection.Socket.ReadLn; 
    // Send a response to the client 
    AContext.Connection.Socket.WriteLn('Hello, ' + sName + '.'); 
    AContext.Connection.Socket.WriteLn('Would you like to play a game?'); 
    // We're done with our session 
    AContext.Connection.Disconnect; 
end; 

Đây là cách bạn có thể thiết lập các TIdTCPServer thực sự đơn giản:

IdTCPServer1.Bindings.Clear; 
IdTCPServer1.Bindings.Add.SetBinding('127.0.0.1', 8080); 
IdTCPServer1.Active := True; 

này cho máy chủ để lắng nghe trên địa chỉ loopback chỉ, tại cổng 8080. Điều này ngăn mọi người bên ngoài máy tính của bạn kết nối với nó.

Sau đó, để kết nối khách hàng của bạn, bạn có thể đi đến một dấu nhắc lệnh Windows và gõ như sau:

telnet 127.0.0.1 8080 

Dưới đây là kết quả:

tên của bạn là gì?

Marcus

Xin chào, Marcus.

Bạn có muốn chơi trò chơi không?

Kết nối với máy chủ bị mất.

Không có telnet? Đây là cách để install telnet client on Vista and 7.

Hoặc với một khách hàng TIdTCP, bạn có thể làm điều này:

var 
    sPrompt: String; 
    sResponse: String; 
begin 
    // Set port to connect to 
    IdTCPClient1.Port := 8080; 
    // Set host to connect to 
    IdTCPClient1.Host := '127.0.0.1'; 
    // Now actually connect 
    IdTCPClient1.Connect; 
    // Read the prompt text from the server 
    sPrompt := IdTCPClient1.Socket.ReadLn; 
    // Show it to the user and ask the user to respond 
    sResponse := InputBox('Prompt', sPrompt, ''); 
    // Send user's response back to server 
    IdTCPClient1.Socket.WriteLn(sResponse); 
    // Show the user the server's final message 
    ShowMessage(IdTCPClient1.Socket.AllData); 
end; 

Một điều quan trọng cần lưu ý ở đây là những điều khoản ReadLn chờ đợi cho đến khi có dữ liệu. Đó là phép thuật đằng sau tất cả.

+7

'Phép thuật' nên được đặt trong chủ đề riêng của nó để ứng dụng có thể tiếp tục trong khi máy chủ không có gì để nói – mjn

5

Khi khách hàng kết nối với máy chủ, máy chủ có sự kiện OnConnect với tham số AContext: TIdContext.

Thuộc tính này là AContext.Connection, bạn có thể lưu trữ bên ngoài sự kiện đó (ví dụ: trong Mảng). Nếu bạn ghép nối nó với IP hoặc tốt hơn nhưng một ID phiên được tạo, sau đó tham chiếu kết nối theo tiêu chí đó, thì bạn có thể có máy chủ gửi lệnh hoặc thông điệp adhoc đến máy khách.

Hy vọng điều này sẽ hữu ích!

+0

Anh ấy hỏi liệu một Khách hàng có thể nghe lệnh từ máy chủ hay không. – LightBulb

+2

Có, và giải pháp này cho phép điều đó! Máy chủ chỉ cần lưu trữ kết nối của từng khách hàng để nó có thể truyền thông điệp hoặc lệnh trực tiếp đến một hoặc nhiều máy khách mà không bị giới hạn trả lời các lệnh máy khách trước! – LaKraven

+0

Và làm thế nào khách hàng sẽ biết rằng nó nhận được một lệnh nếu không có chủ đề lắng nghe ở phía khách hàng? – LightBulb

-3

Với tính năng Indy này không thể thực hiện theo thiết kế:
Chỉ hỗ trợ giao tiếp do khách hàng khởi tạo, điều đó có nghĩa là máy chủ chỉ có thể gửi phản hồi cho các yêu cầu của khách hàng.
Cách dễ nhất (nhưng không phải là thông minh nhất) để có được những gì bạn muốn là sử dụng quy trình kéo. Được kiểm soát bởi một bộ đếm thời gian khách hàng hỏi máy chủ nếu có một lệnh mới. Tất nhiên điều này sẽ gây ra rất nhiều chi phí giao thông và tùy thuộc vào kéo-intervall của bạn có một sự chậm trễ.
Hoặc bạn có thể sử dụng một thư viện như ICS (http://www.overbyte.be/eng/products/ics.html)

+1

Đây có phải là lỗ hổng thiết kế của Indy không? Tôi luôn nghĩ đây là giới hạn TCP ... –

+0

Ồ, trong trường hợp đó tôi đoán chúng ta giống Tom Cruise trong "Mission impossible" vì không có bất kỳ sự lôi kéo nào từ khách hàng, máy chủ của chúng tôi đang gửi tin nhắn tới khách hàng của chúng tôi, ví dụ: nó được tắt, hoặc để cho tất cả các khách hàng kết nối của những thay đổi trong dữ liệu nhất định ... –

+3

IIUC TCP/IP thông tin liên lạc là: 1. Khách hàng kết nối với máy chủ (bên khởi tạo kết nối là khách hàng theo định nghĩa), 2.Cả hai bên có thể gửi dữ liệu bất cứ lúc nào (vì một ổ cắm TCP/IP là hai chiều) – mjn

4

thường khách hàng và phía máy chủ có một sợi được đọc điện tín gửi đến, và gửi điện tín đang xử lý ... nhưng loại giao thức (gửi/nhận, khi nào và cái gì) phụ thuộc vào ứng dụng.

3

Một điểm khởi đầu rất tốt về cách phía máy khách có thể được thực hiện bằng cách sử dụng một luồng, nghe thư từ máy chủ, là thành phần khách hàng Indy Telnet (TIdTelnet trong thư mục Giao thức).

Ứng dụng khách telnet Indy kết nối với máy chủ telnet và sử dụng chỉ một ổ cắm để ghi đọc dữ liệu. Việc đọc xảy ra trong một chuỗi người nghe.

Thiết kế này có thể dễ dàng điều chỉnh để xây dựng phần mềm nhắn tin được phân phối như trò chuyện v.v., và cũng cho thấy giao thức dễ dàng được tách ra khỏi lớp mạng bằng cách sử dụng các ổ cắm chặn.

+0

Tôi đã triển khai một giao thức như thế này trước đây và thành công dựa trên giao thức mã máy khách telnet. – MikeT

6

Nếu lệnh của bạn có văn bản tự nhiên, hãy xem thành phần TIdCmdTCPClient, nó được thiết kế đặc biệt cho các trường hợp khi máy chủ gửi lệnh thay vì máy khách. Máy chủ có thể sử dụng TIdContext.Connection.IOHandler.WriteLn() hoặc TIdContext.Connection.IOHandler.SendCmd() để gửi lệnh.