Skip to content
This repository has been archived by the owner on Dec 16, 2019. It is now read-only.

Socket::accept() and Socket::setBlocking(false) #733

Closed
prolic opened this issue Aug 6, 2017 · 22 comments
Closed

Socket::accept() and Socket::setBlocking(false) #733

prolic opened this issue Aug 6, 2017 · 22 comments

Comments

@prolic
Copy link
Contributor

prolic commented Aug 6, 2017

I am not sure if this is the correct behaviour. But once Socket::setBlocking(false) is called, a call to Socket::accept() throws RuntimeException: socket found in invalid state.

When I remove that setBlocking(false) call, the thread hangs forever during accept() and waits for a connection. This leads to being impossible to shutdown the thread, as I cannot close the socket nor kill the thread (Thread::kill() has been removed).

Is this a bug? If not, how should I proceed?

Environment

  • PHP: 7.2.0beta1
  • pthreads: latest master
  • OS: Ubuntu 16.04 LTS
@sirsnyder
Copy link
Collaborator

I guess this is a bug. Should be easy to fix. Will give it a try the next days.

@sirsnyder
Copy link
Collaborator

@tpunt please add the bug label

@dktapps
Copy link
Contributor

dktapps commented Aug 16, 2017

On a semi-related note, this is also a problem with resources... if you have an application with a thread waiting for a blocking stdin read to complete, for example, you can't stop the thread without user input, and are unable to kill it.

@tpunt
Copy link
Collaborator

tpunt commented Aug 17, 2017

Reading through the accept man page (since Socket::accept uses it internally) shows the following:

If no pending connections are present on the queue, and the socket is
not marked as nonblocking, accept() blocks the caller until a
connection is present. If the socket is marked nonblocking and no
pending connections are present on the queue, accept() fails with the
error EAGAIN or EWOULDBLOCK.

So it would seem that this is expected behaviour. I cannot offer much more advice on this at the moment, though, because I'm not well-versed in the sockets code (yet). I'll try to look more into this in the coming week.

@prolic
Copy link
Contributor Author

prolic commented Aug 18, 2017

Btw: Will is the Tread::kill() method removed? With it I probably could ignore the setBlocking-problem and just kill the thread, when I want to stop the socket server.

@tpunt
Copy link
Collaborator

tpunt commented Aug 18, 2017

I can think of two reasons for removing Thread::kill:

  1. If a thread acquires one of pthread's global mutexes, and you then kill it, the lock will not be released. This could probably be solved with Robust Mutexes, but it isn't something I've looked into.
  2. Killing a thread will not enable for that thread's memory to be released - it will be leaked until the main PHP process ends.

There could be other problems with it too - the above two points were just my guesses of why it was removed.

@prolic
Copy link
Contributor Author

prolic commented Aug 18, 2017 via email

sirsnyder added a commit to sirsnyder/pthreads that referenced this issue Aug 24, 2017
@sirsnyder
Copy link
Collaborator

@prolic please run your socket server with the master branch of my fork https://github.com/SirSnyder/pthreads. I will provide a merge request, if my patch works for you.

@prolic
Copy link
Contributor Author

prolic commented Aug 24, 2017

@sirsnyder I checked out your branch, but make fails on my machine.

@prolic
Copy link
Contributor Author

prolic commented Aug 24, 2017

I just cloned your repo again and same problem. Also on krakjoe's original master branch. Tested with PHP 7.2.0beta3 on Ubuntu 16.04.

@prolic
Copy link
Contributor Author

prolic commented Aug 24, 2017

Oh, nevermind, I just realized I compiled against 7.1.5 accidentally :) Testing now....

@prolic
Copy link
Contributor Author

prolic commented Aug 24, 2017

Unfortunately it's not working.

When I do $this->socket->setBlocking(false); then later in my thread $this->threadSocket = $this->mainSocket->accept(); will have $this->threadSocket = NULL instead an instance of Socket.

@sirsnyder
Copy link
Collaborator

Could you provide a small code example?

@prolic
Copy link
Contributor Author

prolic commented Aug 24, 2017

@sirsnyder you'll find the example here:

https://github.com/prolic/pthreads/blob/socketserver/examples/SocketServer2.php

You only need to add the setBlocking(false) yourself, as this is still missing.

@sirsnyder
Copy link
Collaborator

@prolic I've modified your example https://gist.github.com/SirSnyder/c6fb3e3c730957a25bfcc08b836a92a7. Socket::accept() now returns false instead of null to match the behavior of socket_accept().

sirsnyder added a commit to sirsnyder/pthreads that referenced this issue Aug 24, 2017
@prolic
Copy link
Contributor Author

prolic commented Aug 25, 2017

@sirsnyder Thanks, but it still doesn't seem to work: PHP Fatal error: Uncaught Error: Call to a member function write() on null in /home/sasa/code/pthreads/examples/SocketServer2.php:106

@prolic
Copy link
Contributor Author

prolic commented Aug 25, 2017

Oh wait, I need to add your patch first....

@prolic
Copy link
Contributor Author

prolic commented Aug 25, 2017

Wow, works like a charm !!! Thanks a lot !!

@prolic
Copy link
Contributor Author

prolic commented Aug 25, 2017

@sirsnyder when you provide your PR, would like to include your updated version of #734 as well?

sirsnyder added a commit to sirsnyder/pthreads that referenced this issue Aug 25, 2017
@sirsnyder
Copy link
Collaborator

@prolic with pleasure

@prolic
Copy link
Contributor Author

prolic commented Aug 26, 2017

@sirsnyder I was experimenting a bit the socket server, and I still have one issue:

Once a connection is established (I use telnet for testing) and I try to stop the server, the server will not stop, until I close or finish the telnet session.

BUT: If I do CRTL+C again on the socket server, the server will stop and telnet connection is closed.

I can't figure out what is going on here, maybe you have an idea?

What I wanted to achieve is giving all clients 5 seconds to complete, but then they will all get kicked (similar to what nginx does, when you stop the server, but have an open telnet connection).

sirsnyder added a commit to sirsnyder/pthreads that referenced this issue Aug 27, 2017
@sirsnyder
Copy link
Collaborator

@prolic yes, it's a very similar situation to the first. The spawned socket is in blocking state, read() and write() are hanging forever. I've updated the gist with the sample server extended.

sirsnyder added a commit that referenced this issue Jan 29, 2018
…cept

Fixes #733: accept() recognizes socket blocking state
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants