I'm trying to send a buffer to my socket client when the file descriptor is available for writing.
EV_SET is set to: EVFILT_WRITE, EV_ADD | EV_DISABLE | EV_CLEAR
then when changed to EVFILT_WRITE, EV_ENABLE then EVFILT_WRITE get triggered once which is great!
but if i use the function write or send when i get EVFILT_WRITE like this:
if (e->filter == EVFILT_WRITE)
send(socket, buff, strlen(buff), 0);
then i get again another EVFILT_WRITE event. It seems like the send function trigger another EVFILT_WRITE event. is that expected behaviour? I thought EVFILT_WRITE triggers only when the file descriptor is available for writing.
I searched for the issue, but it looks like nobody mention that. Can someone please confirm if that is expected behaviour and why?
This is how I understand it:
Since you used EV_CLEAR, the kevent facility starts to return state transitions, not the current state. So, whenever you touch the socket descriptor with kevent() or send() calls, you get an EVFILT_WRITE event back.
Another way to look at this:
When send() is called the descriptor becomes unavailable for writing for a moment and then again becomes available, which is why you get an event.
I'll try to loop in some knowledgeable people to this question.
Related
I have been using this code as a sample to receive interface up/down events on a Linux machine. I am able to receive the events correctly but when an interface comes up from a previous down state, I receive multiple netlink events like this:
Event received >> NETLINK::Down
Event received >> NETLINK::Down
Event received >> NETLINK::Up
edit: I have modified a line in this code from:
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
to:
addr.nl_groups = RTMGRP_LINK;
But still I receive multiple events. Can anybody suggest if it is possible to suppress these events to receive a unique event for each state? If so how?
Finally after a lot of research I was able to get this done. There is a flag called "ifi_change" which gives out the change in the Netdevice's state change. I wasn't able to think of it because the rtnetlink man page did not mention anything about it. It says it is reserved for future use and should always be set to 0xFFFFFFFF. However, its value changes upon change in the current state of the interface. If there is a state change it gives a finite value else it is zero. Using this check I was able to suppress multiple netlink messages.
Looking at the code, I suspect you're getting a notification for each of the following types of events:
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
I'd suggest narrowing it down to
addr.nl_groups = RTMGRP_LINK;
(or to IPv4/IPv6 as appropriate.)
in my code i call SSL_do_handshake() function.
Everything works fine if the server gets the "right" messages.
BUT, for security issues I tried sending a dummy message. just "hello" to the right port and the right ip address.
in this case, SSL_do_handshake() gets stuck forever.
I want the function to return in that case, so that my server will not get stuck.
What are the options ?
I read about setting bio to non-blocking..
I added to my code :
BIO_set_nbio(bio, 1); before the connection is established..
but it didn't do thew work...
What can I do ?
BIO_set_nbio sets only the flag, that the bio should be considered non-blocking. You have to actually make the socket itself non-blocking.
epoll TCP with EPOLLOUT | EPOLLET gets event for one time and goes to time out even if I send data after getting the first event.
While in UDP epoll keeps getting EPOLLOUT events after sending new data.
Can you explain this issue?
EPOLLET is edge-triggered mode, which means it will only notify you of state transitions. In this case it will notify you when the file descriptor goes from not being writable to being writable. And the only way to make it not writable is to fill the outgoing buffer. So you need to just keep sending until you get EAGAIN, then you'll wait for a notification.
I implemented my own frame decoder to parse the bytes received through a UDP socket (using NioDatagramChannelFactory and ConnectionlessBootstrap) according to our protocol.
Just to follow what is happening in the server while receiving messages, I added trace logs in each callback method of the decoder.
It appears that for almost every message the server receives, we can see that the event "channelInterestChanged" is received twice in the method channelInterestChanged(). The value of the event is first 0 (OP_NONE) then 1 (OP_READ).
I read the documentation about this, but I am still not sure to understand why I receive such events. I first through it was because the receive buffer (or the selector queue) was full, but the server receives this event the same number of times it receives the "messageReceived" event (before the decode() method is called) and all the messages/frames are properly decoded as expected. When messages are missing, I do no see any event at all. In this case it is probably because the receive buffer of the datagram socket is full. But even if I increase this receive buffer, I continue to see these events and to miss messages.
So, I am wondering why for each message received, the server also receives two "channelInterestChanged", one with the OP_NONE value and one with the OP_READ value. Please, takes note also that in the channel pipeline, after my frame decoder, there is an ExecutionHandler and another business-specific handler (which sends a JMS message to an ActiveMQ instance).
Any idea or explanation for me?
Thank you.
When a DownStreamChannelStateEvent fired from a handler (e.g calling channel.setReadable(), channel.setWriteable()), the event will change the channel's nio selector key's interested option in the NioDatagramWorker, later, a UpstreamChannelStateEvent will be fired with changed option (i.e OP_READ or OP_NONE)
Your frame decoder handler receives UpstreamChannelStateEvents because, some other handlers in the pipeline are changing the channel's read interest options (the purpose of calling channel.setReadable/setWriteable is, throttling the read/write to avoid congestion, OutOfMemoryError in the application).
If you have any MemoryAwareThreadPoolExecutor in your pipeline (which monitors the size of the channel memory used), it may suspend or resume reading by calling channel.setReadable() any time if the channel receives messages too fast. You may have to configure the MATPE instance with optimum maxChannelMemorySize, maxTotalMemorySize or disable it by setting it to 0.
I have a dll written in C.
I would like to send data to a socket and receive the answer in the same function.
e.g.:
BOOL SendToSocketAndRecv(...)
{
// ...
send(...);
retval = recv(...);
// ...
}
In another word, my dll should not follow Client Server pattren.
Is this possible ?
any help ?
Thank you - Khayralla
Yes
You may work in either blocking (synchronous) or non-blocking (asynchronous) mode. Depending on this you may or may not send more data before you receive something from the peer.
"Stream" sockets (like TCP) are "tunnels". If the peer sends several packets you may receive them in a single call to recv, and vice-versa - a sinle "message" from the peer may take several calls to recv. Hence you should read the message in a loop.
You have a lot to learn about network programming.
I am sending a commands to Robot and then wait to get answer
Yes, what you have will work.
But things start to get interesting when you factor in the chance that the robot will not respond for whatever reason. Then you need to provide for a timeout on the response. Soon other things start to creep in. For example, you may not want to be stuck in the read for the duration of the wait, because you may need to service other events (user input or other sources) as they comes in.
A common architecture to handle this is to use select() and make it the hub of all your incoming events. Then you drive a state machine (or machines) off these events. You end up with an event driven architecture. It would look something like this:
while(true)
{
select(fds for event sources, timeout);
if (timeout)
{
call robot state machine(timeout);
continue;
}
iterate through fds
{
if (fd has data)
{
read data into buf
if (fd is for robot)
{
call robot state machine(buf)
}
else if (fd is for source1)
{
call source1 state machine(buf)
}
...
}
}
}
In this model, sends can be done from anywhere in the code. But you wind up sitting in the select() after, waiting for events. Also, you will have to figure out the details of doing the correct timeout and select in general, but there is enough of that out there.
Yes this is both possible and legal. The API itself isn't concerned about being used from the same function.
not only is this possible, it is a classic coding idiom for a client in a client server system. Usually the function is called something like ExecuteRequest