I am sending and receiving data using fsockopen and fwrite. My application receives the proper response, but seems to wait until some sort of timeout before continuing. I suspect that I am not closing the connection properly after it finishes receiving the response, which explains the wait. Could someone take a look at my code?
private static function Send($URL, $Data) {
$server = parse_url($URL, PHP_URL_HOST);
$port = parse_url($URL, PHP_URL_PORT);
// If the parsing the port information fails, we will assume it's on a default port.
// As such, we'll set the port in the switch below.
if($port == null) {
switch(parse_url($URL, PHP_URL_SCHEME)) {
case "HTTP":
$port = 80;
break;
case "HTTPS":
$port = 443;
break;
}
}
// Check if we are using a proxy (debug configuration typically).
if(\HTTP\HTTPRequests::ProxyEnabled) {
$server = \HTTP\HTTPRequests::ProxyServer;
$port = \HTTP\HTTPRequests::ProxyPort;
}
// Open a connection to the server.
$connection = fsockopen($server, $port, $errno, $errstr);
if (!$connection) {
die("OMG Ponies!");
}
fwrite($connection, $Data);
$response = "";
while (!feof($connection)) {
$response .= fgets($connection);
}
fclose($connection);
return $response;
}
The problem is with this line:
while (!feof($connection)) {
Sockets are streams; unless the other side closes the connection first, feof will never return true and your script will eventually time out.
To perform an orderly shutdown both parties have to close their end of the connection; one of them can do it as a response to the other, but clearly if both are waiting for the other to close first then noone ever will.
Does the program on the other side close the connection after outputting something? It seems not.
Related
I have an HL7 machine that sends data via TCP on a specified port. I want to continuously listen on that port and display any data received on the screen.
I have this which creates a connection but in my scenario, connection is created by the HL7 machine which then starts sending.
// host and port to connect to
$host = "localhost";
$port = 9876;
// connect to the port
$fp = fsockopen($host, $port, $errno, $errstr);
set_time_limit(0);
// if connection not successfull, display error
if (!$fp)
{
die("Error: Could not open socket for connection!");
}
else
{
// connection successfull, listen for data (1024 bytes by default)
$got = fgets($fp);
// display the data
echo $got;
}
fclose($fp);
You should wait (block) for a socket connection from the HL7 machine. When a connection is received you should process the data then wait for another connection.
If several connections are made at once and your processing of the HL7 message takes a bit of time, it may be wise to process the message/data from the socket in a new thread.
<?php
$condition = true;
$socket = socket_create_listen(port);
socket_set_block($socket);
while (condition) {
socket_accept($socket);
// read data from socket
// condition to break from listening
}
?>
Reference: http://php.net/manual/en/function.socket-set-block.php
When using stream_select() on an array which contains the server socket created with stream_socket_server() and also the client sockets it always returns instantly with the server socket selected.
My understanding of stream_select() is that it should only return when the server socket state has changed (or timeout is reached). This should only happen if a new client is trying to connect or one client has sent data.
I have written the following code:
$socket = stream_socket_server("tcp://localhost:8888");
$connections['master'] = $socket;
while(true) {
$w = $e = null;
$r = $connections;
if (stream_select($r, $w, $e, 1) !== false) {
foreach ($r as $socket) {
if ($socket === $connections['master']) {
$conn = stream_socket_accept($socket);
$connections[] = $conn;
} else {
// Handle communication with client...
}
}
}
}
With this, I get a non-stop running loop where $r everytime contains the server socket, but stream_socket_accept() throws an error because there is no client trying to connect.
What am I doing wrong? Or is my understanding about stream_select() wrong?
I am about to write a function which returns true or false. If the function is able to connect to the game server (doesn't need anything further, just to check if it's running) via UDP and a specific ip, it'll return true. If not, it'll return false. Unfortunately, I didn't find anything useful by searching the web.
Edit: For TCP, I'm using this and it's working like a charm.
function loginServer()
{
$ipAddr = "localhost";
$port = 1234;
$fp = fsockopen($ipAddr, $port, $errno, $errstr);
if(!$fp)
{
return false;
}
else
{
fclose($fp);
return true;
}
}
i've seen other people with this problem, but maybe i can explain my situation and you can point out where the issue might be.
im getting a 'Warning : socket_bind(): unable to bind address [98]: Address already in use' error.
the situation is this. I am using a web application to trigger another program to perform tasks (from a webpage interface). The results of that program are sent through a socket to my web application that is listening on a socket.
first i create and open the socket, then i trigger the other program, then when that program is finished it should send its results back through the socket.
it works fine the first try. Then the next try (i trigger this process many times) i get the above socket bind error when trying to open the socket, obviously the socket is still bound.
i wait about a minute and i can successfully run the process again. I think the socket connection timesout.
I dont know if the problem is because of the way i have structure my socket code, or if the problem is in the external program that i am triggering. I dont know much about the internals of the external program as its a jar file built by someone else.
heres the code i use for creating and handling the socket. I just used an example on php.net and altered it for my needs.
$port1 = 15000;
// configure the socket
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$address = '127.0.0.1';
$port2 = 54321;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$error = 'none';
if ($sock) {
if (socket_bind($sock, $address, $port2)) {
if (socket_listen($sock, 5)) {
// trigger external process
if (start_calibration()) {
$buf = array();
// listen to the socket for incoming messages
do {
// if incomming connection is not accepted break out and close socket
if (($msgsock = socket_accept($sock)) === false) {
break;
}
do {
// if cant read socket then break out and close socket
if (false === ($buf = socket_read($msgsock, 2048, PHP_BINARY_READ))) {
break 2;
}
$buf = unpack('C*', $buf);
socket_close($msgsock);
break 2;
} while (true);
socket_close($msgsock);
} while (true);
socket_close($sock);
// code to handle data recieved through the socket
}
else {
// start_calibration failed
$error = 'start_calibration failed';
socket_close($sock);
}
}
else {
// socket_listen failed
$error = 'socket_listen failed';
socket_close($sock);
}
}
else {
// socket_bind failed
$error = 'socket_bind failed';
socket_close($sock);
}
}
else {
// socket_create failed
$error = 'socket_create failed';
}
$data['error'] = $error;
echo json_encode($data);
also, is there is a more efficient way to handle the closing of sockets if there is problems with lines like 'socket_bind', 'socket_listen' etc?
Did you try to set the flag SO_REUSEADDR on your socket?
There's a sample in the socket_set_option's documentation.
I'm trying to use a script to query if a Shoutcast Server is online or offline. The code below is what I'm using at the moment.
$vt_ip = "ip";
$vt_port = "port";
$output = #fsockopen($vt_ip, $vt_port, $errno, $errstr, 2);
if (!$output) {
echo "<FONT CLASS=f1 COLOR=#DD0000><B>OFFLINE</B></FONT>";
} else {
echo "<FONT CLASS=f1 COLOR=#00DD00><B>ONLINE</B></FONT>";
}
#fclose($output);
But it doesn't update, it is stuck on Offline status.
Any help would be greatly appreciated.
$vt_ip = "ip";
$vt_port = "port";
$conn = fsockopen($vt_ip, $vt_port, $errno, $errstr, 2);
if(!$conn){
echo $errno;
}else{
fwrite($conn, "\n");
$output = fread($conn, 1024);
fclose($conn);
if ($output == "") {
echo "<FONT CLASS=f1 COLOR=#DD0000><B>OFFLINE</B></FONT>";
} else {
echo "<FONT CLASS=f1 COLOR=#00DD00><B>ONLINE</B></FONT>";
}
}
It isn't enough to simply make a TCP connection to a SHOUTcast server to determine if the stream is working. In fact, a SHOUTcast server that is running will always accept yourTCP connection, even if there is no stream for playback.
You must connect, request the stream, and then check the return status code. Once connected, send this data:
GET /; HTTP/1.0
Follow that by a \r\n\r\n. Now, read data back from the stream until you get the \r\n\r\n. Then, you can disconnect. Check the status code from the first response line and see if it's 200. If it is, you've got an active stream.