I'm writing a tool that connects to a server, sends request, read response, and send other commands.
The problem is that the response the server send can vary in terms of lines (it's always at least one line, but can be 3, 5 lines), and he can send one line, wait a few seconds, then send others lines.
Is there a way to read all the incoming data until they stop?
Maybe I have to change for sockets?
Here are my tries :
$fp = fsockopen("www.example.com", 25, $errno, $errstr, 30);
-
while(fgets($fp, 1024)) {} // hangs
-
fgets($fp, 4096); // works, but doesn't get the multiple lines
-
while(!feof($fp)){
fgets($fp, 1024);
}
// hangs
-
while(($c = fgetc($fp))!==false) {
var_dump($c);
}
// hangs
You are using a TCP connection. A TCP connection will stay open unless one of the communication partners explicitly closes it.
This means
while(!feof($fp)) {
fgets($fp);
}
will hang forever unless the server closes the connection after transfer. (It seems that the remote server does not). This applies to while(fgets($fp, 1024)) {} as well.
The other option would be that the client (your PHP script) closes the connection. This can be done safely only if the client knows the size of the message and can decide when all the bytes has been sent.
Implementing this is a protocol feature, in HTTP for example the content-length header is used.
Having that you connecting to port 25, I assume that you are speaking with an SMTP server. SMTP manages the message length as a protocol feature. You'll need to implement the SMTP protocol.
About:
$message = fgets($fp, 4096);
It "works" only if it is sure that the message will never exceed 4096 bytes. The newlines are still in the result, you simply would need to
$lines = explode("\n", $message);
Related
I have a function which creates a socket connection and listens on a port number for HL7 messages sent by a laboratory machine via TCP.
If the lab machine is not sending anything, my listen function keeps listening. Is there a way to specify that it should listen only for say 10 seconds and then if there are no messages, an error should be thrown?
$address = '0.0.0.0';
$port = 5600;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
$bind = socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);
$client = socket_accept($sock);
// Read the input from the client
$input = socket_read($client, 2024);
// Strip all white spaces from input
$segs = explode("|",$input);
// Close the master sockets
$close = socket_close($sock);
This is the solution:
socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>10,"usec"=>0)); // after 10 seconds socket will destroy the connection. Also you can set and uses
This looks like the XY problem.
That the thing you want to measure acts as a client rather implies that you might want to do more than just detect an open TCP connection in your script, e.g. capture some data. Further, the underlying OS has a lot of complex, well tested, reliable and tunable mechanisms for tracking the state of connections.
While you could do as stefo91 suggests and try to manipulate receive timeout, I'm not sure if this is applied in the wait for an initial connection. A better solution would be to set the socket to non-blocking. Don't forget to either:
inject some calls to sleep()/usleep() or
use socket_select()
unless you want your script to be burning a lot of resource with nothing to do.
But depending on a lot of information you've not told us about, the right solution might be to run one script as a server, and a second as a monitor. The second could be polling/parsing the output of netstat to check the connection.
I see come code from PHP manual
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
writing header by echo, is this going to work?
when just calling simple code like this:
echo 'hello';
where the http headers from?
What you're doing in this code is:
Open a socket connection to a remote HTTP server (www.example.com on port 80). This establishes a TCP connection to that port.
You then send (via fwrite) an HTTP request over this connection. HTTP is a protocol on top of TCP, and you're manually formulating your HTTP protocol headers here.
You're then reading (via fgets) the (HTTP) response of the remote server.
I'm guessing that you want to know why you see HTTP headers in this remote response, even though you're only doing echo 'hello'; on the remote server. The answer is because the web server running on that server is handling the HTTP transaction. You're not handling any details of the incoming HTTP request in PHP, and you're also not handling any details of the outgoing response. The web server on which PHP is running (likely Apache) is doing that.
The whole stack includes a TCP connection, which carries an HTTP request, which consists of HTTP headers and an HTTP body. On the server, the TCP connection is typically handled by the underlying operating system, which makes the connection available as a socket to the web server, where the web server "unwraps" the HTTP request to handle it and invoke PHP if necessary, and then the whole chain goes backwards for the response.
So Im trying to get my head wrapped around this....
I open the port
$remip = $_SERVER['SERVER_ADDR']; //Grab my server address
$fp = fsockopen($remip, 80, $errno, $errstr, 10);//Godaddy hosting only 80 and 443 ports work
//fsockopen(ip address , port, IDK, IDK, timeout delay)
so now the ports open or if not maybe some error checking to be sure
if (!$fp) { echo "$errstr ($errno)<br>\n"; exit; } //Not sure what this echos out but its clear how it stops errors
So now that the port is open any ip/client can connect on this port????
Ill assume I can now connect....
So on my client I open a socket to my server ip address port tcp connection.....
The php file includes something like
else {$out = "hello, 80\r\n"; //out specifies the string to be written , bytes to write
fwrite($fp, $out); //$fp is the handle
fclose($fp)}//close the connection
at this point ill assume that my client gets the hello written to it ..
finish up by closing the connection
Im entirely new to this so Im attempting to understand some sample code here...
So how long is this socket open for? If i want to keep this port open do i need to do a cron job to launch this file periodically.
Im 100% sure that I have got something wrong here so please set me straight.
I think you have a misconception of what fsockopen does. In your example your fsockopen does not actually open port 80 (as in opening a server socket), but it opens a client socket that connects to port 80 on the server itself. It actually does open a (client) port which gets a (not completely) random number.
After you connected using fsockopen you can send HTTP commands to the webserver such as GET /index.php
What you need to use is socket_listen() and socket_bind(). There are a few places in the docs that show you how to get PHP listening on a socket: http://www.php.net/manual/en/function.socket-listen.php
I suggest you read and try them out by simply testing then with a unix tool called netcat (nc <ip_address> <port> command normally)
I have a socket client that connects to a server and waits for lines of text to be sent from the server.
I open the connection with:
$handle = fsockopen(MY_IP_ADDRESS,MY_PORT,$sockErrno,$sockErrStr);
stream_set_blocking($handle,1);
stream_set_timeout($handle,MY_SOCKET_TIMEOUT);
Then:
while (true) {
$inString = fgets($handle,256);
do some stuff with the received data...
}
This all works fine. There is no particular interval between messages received. Messages may arrive several per second or not for several minutes.
The stream_set_timeout is set to 60 seconds... if no message has been received then I just loop around and queue the fgets again.
Once in a while, the connection is broken for one reason or another.
I want to be able to detect the broken connection so I can begin to attempt to reconnect.
Is there a way to detect a broken connection? Is there something I can examine when a stream timeout occurs that will tell me there is no longer a connection?
We are currently using sockets to open and write to a http connection, requests that we don't necessarily care about the response! Like tracking pings etc
This worked on our old servers and on our windows developments environments but not on our new ubuntu servers.
The code we use is as follows
$aUrlParts = parse_url($sUrl);
$fp = fsockopen(
$aUrlParts['host'],
isset($aUrlParts['port']) ? $aUrlParts['port'] : 80,
$errno, $errstr, 30
);
$sHeader = "GET {$aUrlParts['path']}?{$aUrlParts["query"]} HTTP/1.1\r\n";
$sHeader.= "Host: {$aUrlParts['host']}\r\n";
$sHeader.= "Connection: Close\r\n\r\n";
fwrite($fp, $sHeader);
fclose($fp);
if I do a read after the fwrite i can get it all to work from the servers but this defeats the point of doing the request this way compared to just curling the URL
I have tried flush the socket and setting it to non blocking but non of that works! Just doing a read after is the only thing that works!
Any help is appreciated
Edit: I will mention these new servers are AWS based and I have a feeling the socket implementation on them may be different
I am not sure that this is worthy as an answer but I had the exact same problem and that's how I came here. My only difference was that I was trying to execute a request against the server itself.
My solution was in the access management of the server. I had an htaccess file that was blocking anyone from viewing except for my own network and the hitch was that it was also blocking my server from requesting itself.
So maybe it has something to do with the servers access management. Let me know if this helps.
We were using fsockopen and fwrite combo, then it up and stopped working one day. Or it was kind of intermittent. After a little research and testing, and if you have fopen wrappers enabled, I ended up using file_get_contents and stream_context_create functions with a timeout that is set to 100th of second. The timeout parameter can receive floating values (https://www.php.net/manual/en/context.http.php). I wrapped it in a try...catch block so it would fail silently. It works beautifully for our purposes. You can do logging stuff in the catch if needed.
$context = stream_context_create([
"http" => [
"method"=>"GET",
"timeout" => .01
]
]
);
try {
file_get_contents($url, 0, $context);
}catch( Exception $e ){
// Fail silently
}