I have a server in PHP which binds to a port and listens to sockets. My server is started in a PHP script with:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
It then listens to the port:
socket_listen($socket);
When a HTTP message arrives from the client, the server reads the header:
$header = socket_read($socket_new,1024);
and then stores the connection in a Memcache storage. This works for most browsers including safari, firefox and Chrome's Canary. However, it doesn't work on chrome. The browser throws an error message:
WebSocket connection to 'ws://xyz.com:9001/chat_server.php'
failed: Error during WebSocket handshake: Incorrect
'Sec-WebSocket-Accept' header value
My version of Chrome is: Version 38.0.2125.111 m (64-bit)
We had the same issue and we could solve it by increasing the "maximum number of bytes" parameter in the socket_read() function. You can try
socket_tead($socket_new, 2048);
The reason is that websocket header in chrome sometimes is greater that 1024 bytes. So, when your server reads 1024 bytes, it does not get Sec-Websocket-Key parameter and it can not generate valid Sec-Websocket-Accept value.
You can also use fsockopen() and fread() instead of socket_read() function.
Related
I have a PHP script that I use to send emails to my newsletter list in one of my sites.
The script uses STARTTLS for encrypted connections, using the following line to establish the SSL handshake:
stream_set_timeout($s, 35, 0);
if(false == stream_socket_enable_crypto($s, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)){
$msg = "452 failed on tls connection";
} else {
$in_tls = true;
}
The socket $s is set to blocking and is already connected to the remote server after issuing a STARTTLS command and ready to start TLS handshake at this stage. As you can see, I am using stream_set_timeout before the handshake. According to the PHP docs it should abort the handshake after X seconds, but it doesn't seem to affect it.
Now this code works most of the time, but I sometimes run into servers where the TLS handshake would just block indefinitely, causing the script to hang.
I've tried looking into non-blocking solutions, but none of them worked for my PHP version (I use v5.1.6).
The only other option is to somehow monitor this line for timeout (I'm not sure if that's possible), or to somehow transfer the socket handle to another process I can run with a timeout control method.
Anyone knows how to solve this?
You could try to set a timeout on the stream, see php manual for stream_set_timeout($s)
When the stream times out, the 'timed_out' key of the array returned
by stream_get_meta_data() is set to TRUE, although no error/warning is
generated.
Also found this on PHP manual
In case anyone is puzzled, stream_set_timeout DOES NOT work for
sockets created with socket_create or socket_accept. Use
socket_set_option instead.
Instead of:
<?php
stream_set_timeout($socket,$sec,$usec);
?>
Use:
<?php
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>$sec, 'usec'=>$usec));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>$sec, 'usec'=>$usec));
?>
Update: This allowed the OP to move past the issue
ini_set('default_socket_timeout', 1);
I wrote the follwing code in PHP
<?php
$mysocket = socket_create(AF_INET, SOCK_STREAM , 0);
socket_bind($mysocket, '127.0.0.1',1024);
socket_listen($mysocket) or die("unable to listen!");
socket_connect($mysocket , '127.0.0.1' , 1024);?>
and an error showed up says"
Warning: socket_connect(): unable to connect [102]: Operation not supported on socket in /Applications/XAMPP/xamppfiles/htdocs/SOCKTEST.php on line 5"
Where is the problem?
I don't know the goal of your code. But here is a great tutorial for socket programming in PHP.
https://www.christophh.net/2012/07/24/php-socket-programming/
I have tested your code. The error comes if your bind your socket to and address
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, '127.0.0.1');
socket_connect($sock, '127.0.0.1', 1337);
socket_close($sock);
http://php.net/manual/de/function.socket-bind.php
Example from the PHP documentation. Perhaps its better if you use different instances to test your problem that you can connect through your network to another instance or computer. For this you can use vagrant for example.
Servers listen and accept, clients connect. The same socket endpoint cannot be both a server (listen) and a client (connect)
A have problem retrieving remote socket IP and port number.
During following procedure:
$master_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//socket_bind(), socket_listen(), socket_accept()
socket_getpeername($client_socket, $client_address, $client_port);
This works fine on localhost(WAMP), but in production it generates warning:
PHP Warning: socket_getpeername(): unable to retrieve peer name [107]: Transport endpoint is not connected in ...
This is strange, because $client_socket is a proper socket resource, other socket functions such as socket_read() perform as they should; socket_getsockname() also works, binding local IP and port number to assigned variables.
Searching the web gives nothing. Does anybody know what could be the reason of such warning?
I am using fsockopen() to send data via TCP to a remote host:
$s = fsockopen($host, $port);
fwrite($s, $data);
fclose($s);
How can I detect afterwards if the connection was closed (with a FIN) or aborted (with a RST) by the remote host?
According to the documentation socket_last_error() and socket_send() can be helpful for you:
socket_send() returns the number of bytes sent, or FALSE on error.
socket_last_error() returns the last error on the socket
I believe, that PHP is able to detect if the connection was closed, however not sure about this.
Hey guys, I am trying to do some socket programming in PHP.
So I am running a socket "server":
$address = '127.0.0.1';
$port = '9999';
$masterSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($masterSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($masterSocket, $address, $port);
socket_listen($masterSocket, 5);
$clientSocket = socket_accept($masterSocket);
So I open up SSH and run this script. It is running, no errors.
Then I have another PHP script which attempts to connect to this:
$fp = fsockopen("me.com", 9999, $errno, $errstr, 30);
fclose($fp);
but it's giving me:
Warning: fsockopen(): unable to connect to me.com:9999 (Connection refused)
How do I begin to fix this?
You haven't finished the listening socket sequence, you need to call socket_accept to accept new connections. There is an example in the comments in the PHP documentation.
$clients = array();
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,'127.0.0.1',$port);
socket_listen($socket);
socket_set_nonblock($socket);
while(true)
{
if(($newc = socket_accept($socket)) !== false)
{
echo "Client $newc has connected\n";
$clients[] = $newc;
}
}
http://php.net/manual/en/function.socket-accept.php
1) Check if the port is firewalled off. You could use telnet to check this.
2) See if it works when the client and server are on the same machine (I'm guessing from your mention of SSH that the server is remote).
3) If it works locally and you can hit the remote port using other tools then it's going to be tricky. I'd suggest you wail and gnash your teeth for a bit; I'm out of ideas.
EDIT: Heh. Or you could just read Steve-o's answer. Teeth-gnashing is still an option.
I know you said that "me.com" is an example but, just to be sure, socket_bind is expecting an IP address.
From http://php.net/manual/en/function.socket-bind.php :
address
If the socket is of the
AF_INET family, the address is an IP
in dotted-quad notation (e.g.
127.0.0.1).
If the socket is of the AF_UNIX
family, the address is the path of a
Unix-domain socket (e.g.
/tmp/my.sock).
I know the question is very old, but if someone still has this problem, make sure you connect to the SAME address you are listening on,
For example, If you're listening on 127.0.0.1 and your Machine address is me.com, you won't be able to connect to me.com with it, for that you'll have to listen on me.com.
Listening on: localhost:8088
Can only connect via: localhost:8088 // not via me.com:8088
Listening on: me.com:8088
Can only connect via: me.com:8088 // not via localhost:8088