Unfortunately I'm using pretty old Matlab version (R14SP3 from 2005). I'd like to read some UDP packets and analyse them.
As this version of Matlab doesn't contains a package to handle the IP, but it contains Java, I'm trying to use Java to receive the data.
I see that there is socket opening (with netstat/tcpview), I see in wireshark that there is a traffic, but I don't receive it:
socket = DatagramSocket(1900);
socket.setSoTimeout(10e3);
socket.setReuseAddress(1);
packet = DatagramPacket(zeros(1,packetLength,'int8'),packetLength);
socket.receive(packet); %<=here I'm waiting 10 seconds while there is active traffic on udp port 1900
Related
Deplyment environment:
I have created a TCP server using JAVA over windows 10 OS. My TCP client program is written in VC++ and runs on windows 7 OS (I don't have any control over this part of the code, it is a black box to me).
My TCP server code is like this:
Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler);
Following is the TCP connection handler snippet:
InputStream incomingPacketBuffer = this.clientSocket.getInputStream();
OutputStream outgoingPacketBuffer = this.clientSocket.getOutputStream();
int bufferLen=0;
byte inBuffer[] = new byte[this.clientSocket.getReceiveBufferSize()];
byte outBuffer[] = new byte[this.clientSocket.getSendBufferSize()];
while(this.clientSocket.isConnected())
{
bufferLen = incomingPacketBuffer.read(inBuffer);
if(bufferLen>0)
{
outBuffer = (byte[]) this.packetHandlerModule.invoke(this.packetHandler,Arrays.copyOf(inBuffer, bufferLen));
}
if(outBuffer != null)
{
if(this.clientSocket.isConnected())
{
outgoingPacketBuffer.write(outBuffer);
outgoingPacketBuffer.flush();
}
}
}
this.clientSocket.close();
The communication is packet based and the protocol/parsing is handled by packetHandler.
Two more variant I've tried:
I have tried to close the socket as and when a reply is sent back to the client. That is, after receiving one packet of data, I reply to the client and close the connection.
I used inputStream.available before using the read method.
The problem I face:
Most of the time the TCP server replies to incoming packets within a second. If the server receives a packet after some idle time, the server doesn't reply to the packet. Sometimes even when there is active communication is going on, the reply is not being transmitted. Secondly, the isConnected function returns true even when the client socket closed the connection.
Debugging attempts:
I used teraterm to send packets and checked it. The behavior is same. As long as I send packets one after another, I don't have an issue. If one packet doesn't get a reply, then every packet sent after that does not get reply from the server.
When I press Ctrl+C in server console, all the packets sent from teraterm is processed by TCP server and reply is sent back. After this the server works properly for some duration.
I checked the packet flow with wireshark. When the replies are sent back normally, it is sent along with the ACK of client request (SYN, SYN+ACK, ACK, PSH, PSH+ACK, FYN, FYN+ACK, ACK). When the reply gets staled (may not be the right term, it is stuck in inputStream.available or inputStream.read), only ACK packet is sent by server (SYN, SYN+ACK, ACK, PSH, ACK).
I checked many forums and other threads in stackexchange, learned about Nagle's algorithm, applicaion must take care of packetization in TCP, TCP may receive 10+10 packets as 8+12 or 15+5 or any such manner. The server code takes care of packetization, setKeepAlive is set to true (there is no problem when a packet is sent from server).
Problem in short: "At times, TCP read call is getting blocked for a long duration even when there is incoming packets. When Ctrl+C is pressed, they are getting processed."
PS: I just started posting queries on stackexchange, so kindly let me know if there is any issues in the way of formulating the query.
PPS: Sorry for such a long post.
UPDATE
The comment from EJB helped me to identify the peer disconnect.
I made another setup with Ubuntu 16.04 as operating system for server. It has been 3 days, windows system had the issue occasionally. Ubuntu 16.04 never staled.
Some things to consider;
the TCP buffer sizes are usually 8K at least and I don't think you can skink them to 2000 bytes, or if you can, I don't think it's a good idea.
the size of the byte[] doesn't really matter over about 2K, you may as well pick a value.
you can't need to be creating a buffer more than once.
So in short I would try.
Socket s = ss.accept();
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler);
and
try {
InputStream in = this.clientSocket.getInputStream();
OutputStream out = this.clientSocket.getOutputStream();
int bufferLen = 0;
byte[] buffer = new byte[2048];
while ((bufferLen = in.read(buffer)) > 0) {
out.write(buffer, 0, bufferLen); // not buffered so no need to flush
}
} finally {
this.clientSocket.close();
}
At times, TCP read call is getting blocked for a long duration even when there is incoming packets.
Would write a test Java client to see that this is not due to behaviour in Java.
I wrote an application in MATLAB to open a UDP socket and listen for incoming datagrams. Basically, something like this:
u = udp(rHost, rPort, 'LocalHost', lHost, 'LocalPort', lPort);
u.DatagramAvailableFcn = #(o,e) operateOnData(o,e);
fopen(u);
This works wonderfully when I'm listening to something in a unicast fashion. But I would now like to be able to listen to multicast traffic. Apparently, this isn't possible in MATLAB.
The workaround is, per above link,
As a workaround to connect to a UDP multicast, you can do the following:
Use a Java multicast socket to access it directly from MATLAB. For more information, see javadoc or tutorials for the "core java.net" classes from Sun, specifically "java.net.MulticastSocket". This could be found at:
http://java.sun.com/j2se/1.4.2/docs/api/java/net/MulticastSocket.html
I have no background in Java so this is a struggle for me. I've only been able to run the following to instantiate a MulticastSocket object:
>> ms = javaObject('java.net.MulticastSocket');
I looked around and found that I also need a java.net.Datagram object to actually contain the incoming stream.
How do I use the MulticastSocket and Datagram objects within the context of MATLAB? I'm trying to replicate the functionality of u.DatagramAvailableFcn, i.e., fire a callback to operate on the contents of the datagram once I receive one.
EDIT: Looks like this is how I want to go about this in terms of the Java, but now it's getting this back into MATLAB-land...
I successfully subscribed and received a packet from a multicast stream, by the following:
socket = java.net.MultiSocket(streamPort);
socket.joinGroup(java.net.InetAddress.getByName(streamIP));
socket.setReuseAddress(1);
packet = java.net.DatagramPacket(zeros(1, intmax('uint16'), 'int8'), intmax('uint16'));
socket.receive(packet);
socket.leaveGroup(InetAddress.getByName(streamIP));
socket.close;
msg = packet.getData;
msg = msg(1:packet.getLength);
This was essentially lifted from judp availble on the MathWorks File Exchange.
I am still looking for a way to get some equivalent of a DatagramReceivedFcn - right now it looks like the socket.receive call is blocking until it times out. I can use timer objects to fire the "callback" on a regular basis but that's of course not the same as having a DatagramReceivedFcn.
I'm implementing a FTP program using UDP in Java (TCP is not an option), but I'm having trouble grasping the basics of how it's supposed to work.
As I understand, it's connectionless, so I should just have one server thread running which processes every request by any client.
Where I'm getting confused is during the actual file transfer. If the server is in the middle of a loop sending datagrams containing bits of a requested file to the client, and is waiting for an ACK from the client, but instead of that receives a completely different request from a different client, how am I supposed to handle that?
I know I could jump out of the loop to handle it, but then if the initial expected packet finally arrives, how can I pick up where I left off?
A UDP server works similar to a TCP in many respects. The major difference is that you will not receive a acknowledgement that your packets were received. You still have to know which client you are sending to, so use the DatagramSocket class. This is the Oracle tutorial for UDP: http://docs.oracle.com/javase/tutorial/networking/datagrams/index.html. It has a pretty good example in it. The significant part is getting the address and port of the original client, and returning your packets to that client:
InetAddress address = packet.getAddress();
int port = packet.getPort();
new DatagramPacket(buf, buf.length, address, port);
You could start a new thread on the server side for sending the bits every time a client sends a request. The thread would save the return address and port of the client, and die when the file send was done.
I am implementing the TFTP (trivial FTP) protocol in Java. I have a client and a server, and so far the client can request a file and the server sends him that data.
Here is where I hit my problem - for obvious testing reasons, I run both the client and the server on my machine. However, when sending a file, there have to be two sockets listening on the same port:
the client needs to listen for received data packages
the server needs to listen for the client's acknowledgements
...and also two respective sockets for sending data and acknowledgements, also sharing a port.
This normally does happen on the same port, but on different machines. Is there a way to get around this, and make both client and server work peacefully on the same host, without any ugly hacks? And by ugly hacks I mean something like:
predefined offset for the ACK communication port (such as +15 over the data port; this is what I'm currently using now. It sort of works but it feels wrong and is error-prone)
repeatedly closing and opening sockets (send data, close socket used to send data so that the client can use that port to send his ACK, etc.); this also works at the moment, but also via a hack. Here is, for example, how I "reopen" a socket used for sending things:
public void open() {
try {
socket = new DatagramSocket(localPortCache);
} catch (SocketException e) {
e.printStackTrace();
}
}
This is evil. My sockets, originally, receive dynamically-allocated ephemeral port numbers. I then memorize that value and use it to "restore" my socket to the old port. However, it can't be guaranteed that that port is still available. It usually is, but there's no guarantee. Am I being overly-paranoid in this case?
generating a new ACK-communication port in the handshake and send it to the client via the control port (69) in an additional step
Update:
I have managed to fix my problem. My issue was that I wasn't trying to reuse my sockets. For instance, I sent something from a socket on port X, but then tried to allocate a new socket on that port to listen for the ACK, instead of just reusing the old socket.
The client doesn't need to use a fixed port number. Just bind it to zero. The server should send the response back to the originating client whatever its port number.
So I am sending audio over UDP via multicast.
And the sender is sending a raw audio UDP packet every 10 ms. Unfortunately every now and then it misses a packet. So what I did was try to time the send/receive so that I can work out if I have missed one.
Here is what I currently have:
prevReceived = System.currentTimeMillis();
socket.receive(recv);
long messageReceived = System.currentTimeMillis();
if (dateDiff > 20) {
... Missed packet add the previous packet
The problem that I am having is that sometimes the java multisocket receive method is taking 70ms to receive a message. But when I check with Microsoft network monitor the sending is still sending messages.
So I was wondering if there is a way to look at if the multisocket object has any pending packets: socket.count() or something.
or does the datagrampacket received time from the socket time. eg something like recv.timestamp().
So far I have not found anything and cannot work out why it is taking 70ms to process the message when Microsoft network monitor is processing it every 10 ms.
Apache mina can count your datagram packets.
http://mina.apache.org/mina/userguide/ch2-basics/sample-udp-server.html
http://mina.apache.org/mina/userguide/user-guide-toc.html