2015-09-23 46 views
2

我想創建簡單的客戶端和服務器應當由請求 - 響應原理是這樣工作的:如何實現簡單的請求 - 效應初探己技巧沒有缺陷

  • 客戶端發送以下字符串:「do_some_stuff」
  • 服務器做相應的動作,併發送下面的字符串作爲迴應:「成功」
  • 客戶端讀取響應並做一些記錄的東西
  • 一段時間後,客戶端發送新的命令和一切行動再次重複

聽起來容易嗎?不幸的是,我有以下問題:

  • 我應該使用哪種技術來讀取響應?我應該讀取數據,直到某些特定的字符序列發生,或者我應該在某種while true循環中調用read函數並等待連接關閉(我將在響應發送後關閉服務器端的套接字)?
  • 我不明白爲什麼有這麼多的例子只是讀一些字節數(例如,1024),並希望答案將被完全讀取?爲什麼圖書館認爲如果我們說我們應該得到1024字節,那麼在「成功」之後沒有更多的字節?由於服務器端的連接關閉?
  • 如果read_until永遠無法獲取終止字符序列(例如,因爲Internet連接),該怎麼辦?它會無限期地等待嗎?

總而言之,是否可以這樣做?

客戶

#include <boost/asio.hpp> 

#include <iostream> 

int main() 
{ 
    try 
    { 
    boost::asio::io_service io_service; 

    boost::asio::ip::tcp::resolver resolver(io_service); 
    boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), "127.0.0.1", "5013"); 
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); 

    boost::asio::ip::tcp::socket s(io_service); 
    boost::asio::connect(s, iterator); 

    boost::asio::streambuf request; 
    std::ostream request_stream(&request); 
    request_stream << "do_some_stuff\n"; 

    boost::asio::write(s, request); 

    boost::asio::streambuf b; 
    boost::asio::read_until(s, b, '\n'); 
    std::istream is(&b); 
    std::string line; 
    std::getline(is, line); 

    std::cout << "Reply is: " << line << std::endl; 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 
} 

服務器

import socket 
import threading 

def main(): 
    listener = socket.socket() 
    listener.bind(('127.0.0.1', 5013)) 
    listener.listen(5) 
    while True: 
     client, _ = listener.accept() 
     worker_thread = threading.Thread(target=worker, args=(client,)) 
     worker_thread.setDaemon(True) 
     worker_thread.start() 

def worker(client): 
    data = "" 
    while True: 
     packet = client.recv(1024) 
     if not packet: 
      break 

     data += packet 

     if '\n' in data: 
      line, data = data.split('\n', 1) 
      print line 
      client.sendall('success\n') 

if __name__ == '__main__': 
    main() 

有不便不對的解決方案?順便說一句,爲什麼client.recv(1024)在這裏完成之前從套接字接收1024個字節?它如何知道它後面沒有數據?它是如何工作的?

在此先感謝。

回答

1
  • 最常用的方法是使用一個首標指定的長度,並且直到接收到所有的字節讀 。使用消息分隔符也是 使用了很多。等待連接結束可以爲無連接 通信完成,這意味着建立連接,發送消息 (和回覆)並關閉每個消息,效率較低。

  • 使用一次讀取獲取tcp消息的所有字節是一個常見的 錯誤,通常總是適用於短消息。 的錯誤在於tcp是流協議,而不是消息協議。 但是,tcp主要用於傳遞消息。長度 參數應該是緩衝區的大小,而不是字節的預期數字 。讀者知道它什麼時候可以返回,因爲發件人 發送數據包。

  • 當連接丟失而沒有通知的機會(例如電源 關閉,電纜斷開)時,可能會導致無盡的等待。一個可能的 解決方案是tcp_keepalive

+0

非常感謝您的回答!所以,我的代碼應該在所有情況下都能正常工作,對嗎? – FrozenHeart

+1

沒有測試沒有保證,但它對我來說看起來不錯。 – stefaanv

+0

謝謝!以及'client.recv(1024)'如何決定何時結束讀取數據? – FrozenHeart