so what I'm trying to do is understand how sockets work and how to make a simple server for communication between the server and the client application
I tried to accomplish this using AS3 with the project named Red Tamarin (Runs AS3 code on console but it doesn't really matter at the moment)
I managed to create a basic server, It's functionality is basically this:
creates a socket and activates these on it: listen() , accept(). when it accepts, it also adds the new socket received from the accept() to an array of connections.
a for loop that runs according to the length of the connections array and runs receive() on each socket (I didn't call listen() / accept() on those connections, should I?)
My actionscript 3 application connects to the server successfully,
And then for a testing purpose I decided to write() to the server from the client non-stop, just to make sure that the server really is getting the data so I can actually go further into adding more functionality..
But the server doesn't seem to get any further information at all..
It seems to respond only to connection / disconnection, but not really listening between them for any other info..
I know that showing my code would be better, but for now I'd like to know if I'm approaching this correctly, I read about it on the internet and it seems like I am but I came here just to make sure..
Thanks in advance!
EDIT:
I was requested for some of my code, here it is, well the most important parts at least
private var _connections:Array;
private var _socket:Socket;
private var _server:Client;
private var _running:Boolean;
private var _port:uint;
private var _address:String;
public function Server(address:String, port:uint)
{
_connections = [];
_address = address;
_port = port;
_running = false;
_socket = new Socket();
}
public function start():void {
_socket.bind(_port, _address);
_socket.listen(128);
_running = true;
_server = new Client(_socket);
_addClient(_server);
_start();
}
private function _start():void {
while (_running) {
_loop();
}
}
private function _addClient(client:Client):void {
_connections.push(client);
}
public function _loop():void
{
var i:uint;
var selected:Client;
var newconn:Socket;
for (i = 0; i < _connections.length; i++ ) {
selected = _connections[i];
if (selected.hasData()) {
if (selected == _server) {
//accept a new client connection
newconn = _socket.accept();
if (!newconn.valid){
//Invalid.
}
else {
//Add a new client
_addClient(new Client(newconn));
}
} else {
//Read data from clients
selected._socket.receive();
}
}
}
}
Just to answer your listen()/accept() question, you only need to call listen() once when the server is initially set up. Afterwards, you will need to execute accept() for each new client connection you want to make (as accept() will return a socket file descriptor that handles the new client).
After the client is accept()ed, then you will use the socket file descriptor of the client to receive() or send() any data.
look at this example
https://code.google.com/p/spitfire-and-firedrop/source/browse/trunk/socketpolicyd/src/spitfire/SocketPolicyServer.as
in your main loop from what I see in your code you only check if you can read the current socket, you need also to check if you can write to the current socket
also note that everyone has a socket handle, the server and the clients
my guess is you get a bit confused between the Server and Client classes that both wrap a Socket object, try to use only the Socket objects (as in the example above)
and when you understand that then you can go further and abstract/structure bigger classes
Related
I'm writing a code which uses routers' identities to dynamically manage the peers.
To do that, I build the messages with target identity in the first frame, and then I send them trough a router socket to the appropriate peer. If a peer with that identity doesn't exist, I'll create a new one.
In code is something like that:
Main.cpp
zmq::socket_t sendSocket(*_pZmqContext.get(), ZMQ_ROUTER);
// It forces to throw an exception when peer doesn't exists, so I can create a new one.
sendSocket.setsockopt(ZMQ_ROUTER_MANDATORY, 1);
sendSocket.bind("inproc://processors");
...
try
{
...
isSuccess = message2send.send(sendSocket);
...
}
catch (zmq::error_t& ex)
{
if (ex.num() == EHOSTUNREACH)
{
// new peer is created (see OtherRouter.cpp)
...
}
}
...
OtherRouter.cpp
// This is how reader sockets are created...
zmq::socket_t reader(*_pZmqContext, ZMQ_ROUTER);
reader.setsockopt(ZMQ_ROUTING_ID,(std::byte *)&newIdentityValueForSocket[0],sizeof(newIdentityValueForSocket)); ;
reader.connect("inproc://processors");
assert(reader.connected());
...
This works fine, but I need some extra.
Some peers might be destroyed due to inactivity, and being recreated later, when activity is back.
When this happen, code is not working as expected. Even the peer is created successfully, I'm getting EHOSTUNREACH exception. It's like sockets can't communicate again..
So, It seems the sender socket knows that the older peer has been disconnected, but It can't connect to new one.
Any suggestion about how to solve it ?
Thanks!
I have written a threaded server much like this one: https://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp
And a client: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_tcp_client.cpp
They seem to work fine together when the client is talking directly with the server session. But now I would like to create another thread that would use the servers ioservice to send small messages. How would this be possible? I have read that shared_ptr would be one option, but have not got it working...
Inside the session class I define:
typedef boost::shared_ptr<session> session1;
static session1 create(boost::asio::io_service& io_service)
{
return session1(new session(io_service));
}
Then I define a global session_ptr as
session::session1 new_session1 = nullptr;
Then in the acceptor I start the session as:
new_session1 = session::create(tcp_io_serviceServer);
acceptor_.listen();
acceptor_.async_accept(new_session1->socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error));
and in the handle_accept:
new_session1->start();
Now what I would like to achieve, is that when the async_read of the server session gets a message from client to start a new thread:
if (dataReceived[0] == _dataStartCameraThread)
{
pthread = boost::thread(boost::bind(StartProcess, server));
}
then in that thread I want to send messages to the client as: new_session1->write1(error) as
void write1(const boost::system::error_code& error)
{
boost::asio::async_write(tcpsocket, boost::asio::buffer(sbuf, 1), boost::bind(&session::handle_dummy, this, boost::asio::placeholders::error));
}
But without the shared_ptr approach I cannot make this work. It claims that the file handle is not valid.
And using the shared_ptr approach I cannot seem to write anything from the server side, I can only read:
write failed. The file handle supplied is not valid
I checked that the socket is closed even though it just received the message.
Any suggestions where I should go here?
Thank you!
I am developing a server and client project with Qt. I want to print the connection status for the users. For this propose I use state() like:
socketState = mySocket.state();
if (socketState == 3) {
Print("we have connected");
}
However, it does not work when the server queues new connections. To make it clear, my client state is 3 even if the server has paused accepting new connections:
//server side:
myServer->pauseAccepting();
//client side:
connectToHost()
socketState = mySocket.state();
Now the socketState is 3 instead of 0 or a special number for queue state.
To sum it up, I want to know how to inform the client that it is in the queue? Is there anything like state() that has a return value for queue state?
Finally I could find the answer.
The refused client that goes to the queue (by OS) is not different with other clients. Therefore, we can make a special socket for it (which means it is NOT in queue anymore) and start communication (inform and close).
for example:
QTcpSocket clientSocket
QTcpSocket queueSocket
In my project, the server first send a message to the queue client.
The message is:
"We can NOT accept a new client because we can NOT handle more than one". So, it knows what is the problem.
Then, the server closes the queue client socket.
We SHOULD close it because we do NOT want to handle lots of clients.
However, the main point is that we can work with clients in the queue and decide how to deal with them . I prefer to accept them just to inform and close them.
if (we have NOT a client) {
work with clientSocket
}
else {
queueSocket.wirte("We can NOT accept a new client because we can NOT handle more than one")
close queueSocket
}
I hope it helps those who want to inform rejected clients.
I have an issue with my websocket.
I have recently switched my server from PHP to c++ side, and used the POCO library, i used exactly this script:
WebSocketServer.cpp
For the one client side in c++ i used a snipet i found here on stackoverflow:
WebSocketClient.cpp
I modified the client a bit, first it sends a default message as soon as i connect to the server.
I wrapped the whole thing with an Update function from my main app, that I am constantly able to recieve messages:
void CLeagueStats :: Update( ) {
if(m_Connected) {
string msg = Recv( );
if(msg != "") {
//handleIncomingMsg( msg );
}
} else if(GetTime() - LastReconnectTime > 90 || LastReconnectTime == 0) {
Connect( );
}
}
string CLeagueStats :: Recv( ) {
char receiveBuff[256];
int flags=0;
int rlen=m_psock->receiveFrame(receiveBuff,256,flags);
CONSOLE_Print("Recv: "+string(receiveBuff));
return string(receiveBuff);
}
I have now written a totally simple javascript client which is initalizing on page load:
<script type="text/javascript">
var ip_port = 'localhost:9980';
var ohc;
if (typeof (MozWebSocket) == 'function')
ohc = new MozWebSocket('ws://' + ip_port);
else
ohc = new WebSocket('ws://' + ip_port);
var self = this;
setTimeout(function() {
self.ohc.send("hey");
}, 500);
</script>
The server log includes both messages:
C++ App:
WebSocket connection established. Frame received (length=5, flags=0x81).
Javascript:
WebSocket connection established. Frame received (length=3, flags=0x81).
But the log from the C++ App does send the connection message and recieve it back, but i dont get the message from the js-client:
[Websocket] Connecting to websocket.
[Websocket] Send: hello
[Websocket] Recv: hello
Why this happen?
Isn't the snippet form the servercode directly sending the message back to all clients?
n = ws.receiveFrame(buffer, sizeof(buffer), flags);
app.logger().information(Poco::format("Frame received (length=%d, flags=0x%x).", n,unsigned(flags)));
ws.sendFrame(buffer, n, flags);
Is there anything wrong with the code?
I am not a situation to reproduce the environment but I had a similar issue using Python and IOS web sockets. Every other technology we used was working in with Python Sockets flawlessly but IOS web socket had problem. After many days later we find out that IOS web socket does not send a communication ender (EOM) that Python can process. So the we had to handle different IOS sockets different.
I have checked WebSocket flags 81 so it is text and frame is finish. But I would suggest you to check from Developer Tools of browser to see what is recieved over the socket connection from Network Tab.
I may be problem of End of Message did not understood by javascript WebSocket. If you see the data hello on developer tools then it would be easy to handle with situation. However if you don't see any message coming then the problem is most probably from C++ code.
In attachment you can see how Chrome shows the socket data transactions. Keep in mind that clicking on the connection on the left list will update the transactions they are not live.
Hope this helps you.
If not go deeper using tcpdump or similar sowftware to be sure if they really sent and got by two sides.
My application have an asio server socket that must accept connections from a defined List of IPs.
This filter must be done by the application, (not by the system), because it can change at any time (i must be able to update this list at any time)
The client must receive an acces_denied error.
I suppose when the handle_accept callback is called, SYN/ACK has already be sent, so don't want to accept then close brutally when i detect the connected ip est not allowed. I don't manage the client behavior, maybe it doesn't act the same when the connection is refused and just closed by peer, so i want to do everything clean.
(but it's what im soing for the moment)
Do you know how i can do that???
My access list is a container of std::strings (but i can convert it to a countainer of something else....)
Thank you very much
The async_accept method has an overload to obtain the peer endpoint. You can compare that value inside your async_accept handler. If it does not match an entry in your container, let the socket go out of scope. Otherwise, handle it as required by your appliation.
I don't know the details of your app, but this is how I'd do it.
In the accept handler/lambda
void onAccept(shared_ptr<connection> c, error_code ec)
{
if (ec) { /*... */ }
if (isOnBlackList(c->endpoint_))
{
c->socket_.async_write( /* a refusal message */,
[c](error_code, n)
{
c->socket_.shutdown();
// c fizzles out of all contexts...
});
}
else
{
// successful connection execution path
}
}