2010-11-09 36 views
5

Chỉnh sửa: Xin lỗi, vô tình được đăng với tiêu đề cho một câu hỏi khác. Đã sửa.Không thể đọc từ ổ cắm (treo)

Hey guys,

Tôi đang sử dụng PHP để kết nối với một máy chủ C ổ cắm địa phương ++ để giữ trạng thái giữa một ứng dụng web và một vài daemon. Tôi có thể gửi dữ liệu đến máy chủ socket nhưng không nhận được dữ liệu từ nó; nó chỉ chặn trên socket_read() và treo vô thời hạn. Tôi quên một cái gì đó câm (giống như một nhân vật NULL hoặc một sự kết hợp khác nhau của các ký tự dòng mới)? PHP là dưới đây:

socket_connect($sock, $addr, $port); 
socket_write($sock, 'Hello world'); 
$str = ''; 
while($resp = socket_read($sock, 1000)) 
    $str .= $resp; 
socket_close($sock); 
die("Server said: {$str}"); 

Phần liên quan của máy chủ socket nằm dưới (lưu ý <<>> nhà khai thác đang quá tải):

std::string data; 
sock >> data; 
sock << data << std::endl; 

đâu >> cuộc gọi Socket::recv(std::string&)>> cuộc gọi Socket::send(const std::string&).

Điều này làm việc tốt từ (ví dụ) telnet, nhưng PHP không muốn chơi tốt. Bất kỳ suy nghĩ/đề xuất được đánh giá cao.

+1

Bạn đang sử dụng thư viện socket nào cho C++ hoặc bạn đã tạo riêng của mình (* nix hoặc Windows)? Ngoài ra, lỗi là gì? Có phải nó chỉ chặn vĩnh viễn trên sock >> dữ liệu hoặc là một cái gì đó nhiều hơn xảy ra? Tôi đã không được sử dụng giao tiếp PHP với một máy chủ C + + trong một thời gian, nhưng là máy chủ của bạn gửi một chấm dứt vào ổ cắm để nó nói với PHP để ngừng đọc? Vòng lặp của bạn sẽ đọc liên tục trong PHP cho đến khi máy chủ thông báo rằng socket được thực hiện gửi thông tin; nó không phải là một cập nhật thời gian thực tâm trí bạn (kể từ khi nó in dữ liệu sau khi nó đã được hoàn toàn thu thập và lưu trữ trong bạn var). – RageD

+0

Điều này có thể bị thiếu trong mã của bạn, nhưng bạn có 'socket_create' $ sock trước không? – netcoder

+0

Ngoài ra, tôi không thấy điều này trong mã của bạn, nhưng bạn sẽ cần in $ str khi vòng lặp của bạn hoàn tất. – RageD

Trả lời

7

Ổ cắm trong PHP , như trong hầu hết các ngôn ngữ lập trình, được mở trong chế độ chặn theo mặc định, trừ khi được đặt khác bằng cách sử dụng socket_set_nonblock.

Điều này có nghĩa là trừ khi hết thời gian chờ/lỗi hoặc dữ liệu được nhận, socket_read sẽ treo ở đó mãi mãi.

Kể từ khi nhân vật của bạn chấm dứt có vẻ là một dòng mới, hãy thử rằng:

while($resp = socket_read($sock, 1000)) { 
    $str .= $resp; 
    if (strpos($str, "\n") !== false) break; 
} 
socket_close($sock); 
die("Server said: $str"); 
+0

Thật vậy, tôi biết họ chặn theo mặc định nhưng tôi hoàn toàn quên hoặc là a) đóng socket sau khi phản hồi được viết hoặc b) ngắt vòng lặp. Cảm ơn vì điều đó. Sử dụng một ký tự NULL dường như không hoạt động nếu tôi chuyển đổi nó, mặc dù (lý tưởng nó không phải là một dòng mới) - nếu tôi cố gắng 'strpos ($ str," \ 0 ")' sau 'sock << data < <"\ 0" ', nó không bắt được. Có suy nghĩ gì không? – mway

+0

Không giống như C hoặc C++, PHP không đặt byte rỗng vào cuối chuỗi, đó là lý do tại sao 'strpos' với' \ 0' tạo ra boolean false khi được kiểm tra. Bạn phải cung cấp một dấu phân cách khác, sử dụng hết thời gian chờ (xem [Cách đặt thời gian chờ trên socket đọc?] (Http://stackoverflow.com/questions/389645/)), hoặc đóng socket từ phía máy chủ. – netcoder

+0

Đủ công bằng - chỉ nhận ra rằng thông qua thử nghiệm trên đầu của tôi là tốt. Cảm ơn bạn đã giúp đỡ! – mway

0

Tôi thực sự vừa khắc phục sự cố tương tự như vậy, ngoại trừ với các đường ống (Is php's fopen incompatible with the POSIX open for pipes). Tôi không biết giải pháp sẽ tương tự như thế nào, nhưng có thể đáng xem? Tôi đồng ý với RageD rằng bạn nên dán một cout giữa các dòng đọc và viết chỉ để kiểm tra và xem nếu C + + được treo trên sock >> dòng dữ liệu hoặc sock < < < dòng dữ liệu ...

1

socket TCP thường cố gắng kết hợp nhiều gửi nhỏ gọi thành một gói để tránh gửi quá nhiều gói tin (Nagle's algorithm). Đây có thể là nguyên nhân khiến bạn không thể nhận được bất cứ điều gì sau cuộc gọi send(). Bạn sẽ phải mở ổ cắm với TCP_NODELAY để tránh điều đó.

0

Bạn cũng có thể thử điều này khi đọc từ ổ cắm:

if(socket_recv ($socket , $response , 2048 , MSG_PEEK)!==false) 
{ 
    echo "Server said: $response"; 
} 

Lưu ý: Sử dụng MSG_WAITALL ở vị trí của MSG_PEEK có thể gây ra ổ cắm để treo (từ một trong những kinh nghiệm mà tôi đã từng có).

Các vấn đề liên quan