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.
Related
I've a webhost and I want to create a socket connection with my application .
I've this code :
<?php
$host = "127.0.0.1";
$port = 25003;
// don't timeout!
set_time_limit(0);
if (!extension_loaded('sockets')) {
die('The sockets extension is not loaded.');
}
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
echo "Client Message : " . $input;
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>
when I run the page , it returns "Could not create socket"
I'm running the code on a share web service
what is the problem ? How can I fix it ?
I tried your code on my machine with XAMPP installed and is working, it actually does open that port, I tested with telnet through putty. Answering to your questions I think like #Jon Stirling said your hosting does not allow you to create a socket. That's why hosting companies sell web hostings packages and virtual private servers, if you want to bind a port you should look for a VPS.
I am sure you have solved this and moved jobs since you posted it but as someone who has just gone through this I would like to direct everyone who lands here to this page:
https://www.php.net/manual/en/function.socket-select.php
I was looking for a way to have a socket server that does not chew up CPU cycles and only does something when there is something to do. That solution blocks while it is waiting for connections to do something then it processes them.
Pay special attention to the comments about setting $tv_sec to null as this is the "Make Work" flag that prevents chewing up the CPU.
This allows one to create a socket server in PHP that does not chew up CPU and also processes multiple connections.
The only missing piece of the puzzle is disconnecting clients that do not disconnect themselves.
Unless there is a connection timeout that can be set I think the solution is to set $tv_sec to some suitable value, like 2 seconds, and then track the time a connection has been connected then disconnect it if it breaches some time. The downside to this is it will use CPU but if you unblock every 2 seconds then you can use that to process timeouts etc. Otherwise, you have to rely on clients disconnecting. That may not be an issue for you but in my particular usecase it is.
I've got a Python server which multiple clients connect to using sockets. At the moment one server isn't able to cope with the load so I'm looking at ways to split the clients up according to some criteria such as their username.
The intention is to put clients with usernames starting with A-G on server 1, H-P on server 2 and P-Z on server 3.
What I'm trying to do is to write a process that will listen for connections on port 45000 and will then forward those on to the appropriate server on 45001, 45002 and 45003.
At the moment, when a client connects to the original server they connect via a TCP port e.g. 45000. The server checks that they are authorised and responds on a random port with a handshake e.g. 59117, 60647 or 61573.
The response port is not specified when the client first connects so my question is, when is the value determined and how does the client know to listen on that port for the reply ?
So far I've written a PHP process which takes the data from the clients and forwards it to the appropriate server but I can't work out which port to listen on for the response back from the server. Is there some way that PHP sockets can negotiate the response port so that it can be stored in a variable in my script ?
Here's my basic connection code in PHP. I have no knowledge of Python so this is going to have to be done in PHP:
// Define remote Server
$socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Open socket on remote server to send $buf data to
socket_connect($socket, 'X.X.X.X', 40149);
echo ("Forwarding data ($buf) to $socket ....\r\n");
$bytesWritten=socket_write($socket, $buf, strlen($buf));
echo ("Wrote: $bytesWritten bytes\r\n");
// Now listen for response but this will be on another socket
// How do we know what this is ?
if (false === ($response = socket_read($socket, 16384))) {
echo ("Response: $response\r\n");
}
This is way out of my comfort zone so I may have this completely wrong but an afternoon spent Googling has turned up any answers yet.
I have some embedded devices which connect to their sever (supplied software for windows) running on port 6000.
I'm confused as to how this works as my understanding is that when a tcp connection is made on a port, that's it, the port is occupied an no other connections can be made.
But I guess this logic is wrong as multiple devices can connect to their server software just as a web server can accept multiple connections on port 80.
When I run netcat on an ubuntu server with the command nc -l -k 6000 it seems to do what I want, I can see the messages coming in one after another from multiple devices.
From the netcat manual:
-k Forces nc to stay listening for another connection after its cur-
rent connection is completed. It is an error to use this option
without the -l option.
I tried to achieve a similar scenario with php but I failed. Here's what I have so far:
<?php
$address = "0.0.0.0";
$port = 6000;
$mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($mysock, $address, $port) or die('Could not bind to address');
socket_listen($mysock, 5);
$client = socket_accept($mysock);
while (true) {
$input = socket_read($client, 1);
echo $input;
}
?>
I can see the first message from the first device that connects but after that nothing. Also this seems to be the wrong approach as the while loop causes high cpu usage.
Note I'm running the php script at the command line on an ubuntu server.
I realize that this code will only accept one client, but how can I change it so that it will behave like nc and accept multiple connections. Sorry if the question seems vague, I really don't know where to begin. Any help is appreciated
I'm trying to make a simple listener on port 8195. When I try the following code block in PHP CLI conditions, it only shows 'Test' once, then hangs. If I delete the file 'votifier.run', the file designed to be the on/off switch, it still continues to hang. It never shows 'Client connected'.
Furthermore, if I try to connect to the host via Telnet on port 8195 while the script is running, I simply get a connection failed message. It's like it's looking for one connection and just not giving up.
// Set the IP and port to listen to
$address = 'localhost';
$port = 8195;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);
// Loop continuously
while ( file_exists('votifier.run') ) {
echo 'Test';
$client = socket_accept($sock);
if( $client ) {
echo 'Client connected';
// Don't hang on slow connections
socket_set_timeout($client, 5);
// Send them our version
socket_write("VOTIFIER MCWEBLINK\n");
// Read the 256 byte block
$block = socket_read($client, 256);
...
The answer:
socket_accept() will usually hang until a connection is made. If a connection attempt was made, the script would continue, but because the socket was being created on localhost, it would only accept connections to it from localhost.
The fix is to use your external IP rather than 'localhost' or '127.0.0.1'. Then you can Telnet to it.
I'm just guessing here, but could it be that the address you are trying to bind to should not be a hostname?
If the socket is of the AF_INET family, the address is an IP in dotted-quad notation (e.g. 127.0.0.1).
EDIT
Ok, I've taken your script and tried to reproduce your error but couldn't. There are a couple of flaws in it but none that would cause a telnet client's connection attempt to fail.
Since none of the aforementioned applies, let's go thru the checklist one by one:
sockets module loaded/compiled
localhost does resolve to 127.0.0.1
the port isn't taken by any other application running
there's no rule of any sort of firewall that would prevent communication between the telnet client and your server
the machine which you connect from is allowed to connect to the server host (try the same host if it isn't)
the file that's being checked in the while-loop does exist
you are sure that there isn't another fatal error within your script that would prevent the snippet you posted from running
These are all the possible error sources I can think of, atm. Try fixing up the minor flaws first, then go thru the checklist.
if( $client ) {
echo 'Client connected';
// Don't hang on slow connections
socket_set_option(
$client,
SOL_SOCKET,
SO_RCVTIMEO | SO_SNDTIMEO,
array('sec' => 5, 'usec' => 0)
);
// Send them our version
socket_write($client, "VOTIFIER MCWEBLINK\n");
^^^^^^^
// Read the 256 byte block
$block = socket_read($client, 256);
You should be using threads. If the client never sends anything your code will block in the read() method. Each accepted socket should be completely handled in a new thread.
You may want to check this:
PHP Votifier example for Minecraft Topsites
It explains how the code works, it's the basic function that makes the encryption, fills up the 256 blank spaces and sends the packet too. You can work a little with it as you may want to improve it.
You can see a live demo of the running php for the plugin here: http://topg.org/test_votifier
I'm working on a site that connects to many URLs at once, (we are hoping to get to ~600 per minute) and no matter what I try, there are always thousands of TIME_WAIT still open. I understand these are vital to TCP connections, but they are using all the available ports. PHP doesn't have a SO_REUSEPORT, and SO_REUSEADDR doesn't work with remote connections. Here is the beginning of the code:
$s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($s, SOL_SOCKET, SO_LINGER,array('l_linger'=>0, 'l_onoff'=>0)); //I have tried l_onoff=1
socket_set_option($s, SOL_SOCKET, SO_RCVTIMEO,array('sec'=>0,'usec'=>500000));
socket_set_option($s, SOL_SOCKET, SO_SNDTIMEO,array('sec'=>0,'usec'=>500000));
socket_set_option($s, SOL_SOCKET, SO_KEEPALIVE,0);
socket_set_option($s, SOL_SOCKET, SO_REUSEADDR,1);
socket_set_nonblock($s);
socket_bind($s,$ip,0);
socket_connect($s,$host,$port);
The $s goes into an array contains all the pending writes, after a write we call socket_shutdown($s,1); to close writing on the socket. Then after a read we:
socket_shutdown($s,2); socket_close($s);
All reading and writing is done in a while loop, the loop has a max of 12 concurrent connections, if that is not hit, then it moves on and proceeds to add another URL to the array. Every loop calls socket_select with a timeout of 0.
Does anyone have any suggestions? I would like to increase the speed as well as reduce the TIME_WAIT's that appear in netstat.
Thanks,
James Hartig
You could send the HTTP header Connection: close along with your request which would cause the server to send a TCP FIN after it sends you your request. Because the other side sends the first FIN, it'll be the other side that gets to wait around in TIME_WAIT, not you.
If you want to reduce TIME_WAIT on Linux, you can modify a proc setting:
echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
This will change the timeout to 30 seconds. Note that TIME_WAIT is a part of standard TCP/IP behavior - unless you are really starved for resources, I wouldn't muck with this much.