3

I have simple C server and Java client. I'm sending text file line by line from server to client:

    do {
        send(sockfd, line, strlen(line), 0);
        printf("%s\n", line);
    } while ((fgets(line, 100, fp)) != NULL);  

and read it in Java client with:

    Client.getCl().getInputStream().read(inmsg);
    do{             
         decoded = new String(inmsg, "UTF-8");
         System.out.println(decoded);
    }while(Client.getCl().getInputStream().read(inmsg) > 0);  

My problem is that I don't know how to send "end of read" from server to client. The client freezes on last read. I know that methode read() returns integer with number of recieving bytes and -1 when there is nothing to read and 0 when the length of buffer is zero. The only solution which returned -1 to client was to close socket on server side, but I can't use that. Also I've tried following:
1) Send 0 length at the end of sending method to tell client, that length is zero:

send(sockfd, NULL, NULL, 0);  

2) Define flags and send:

#define MSG_FIN 0x200
#define MSG_EOR 0x0080

and again with both flags:

 send(sockfd, NULL, NULL, MSG_FIN);
 send(sockfd, NULL, NULL, MSG_EOR);  

Anyone please help what am I doing wrong here? Thanks

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Stepan Tuhacek
  • 219
  • 5
  • 18
  • 2
    I know you said you can't use it, but _why_ can't you close the socket on the server? If you're not willing to close it, doesn't that mean that you're going to send something else later? And if that's the case, then Java should still be able to read, right? – Joshua Taylor Dec 18 '13 at 19:26
  • You'll probably want to figure out ahead of time how many bytes you're going to send, and prefix your data with that number so that the client can determine when to stop reading. It's like the [`Content-Length` header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13) in HTTP. – Joshua Taylor Dec 18 '13 at 19:35
  • If you need to send distinct "messages" over a TCP connection, that's an application-level concern that you have to implement and handle yourself. TCP doesn't really concern itself with that. (UDP does but its unreliability likely makes it unsuitable for your use case. I.e. not media streaming or P2P.) – millimoose Dec 18 '13 at 19:42
  • Now, unless this is a school assignment, what I'd do is get some sort of messaging middleware that *does* handle this. The simplest one I can think of that works across C and Java is probably [0MQ](http://zeromq.org). If your use case is text-based, you could also do what HTTP does where an empty line signifies the end of request headers – you'd have to make sure to flush the socket explicitly after sending the message of course. When the client receives a blank line, it will go and do something else, then get back to the socket later. – millimoose Dec 18 '13 at 19:43

2 Answers2

5

If you want to send intermittent data over the same TCP socket, you'll need to encode the boundaries of the information you're sending within the data you're sending. An example of this is to send "packets" of data with a length-prefix, so that the receiver of a packet will read as many bytes off the socket as the length-prefix says to.

MischaNix
  • 730
  • 3
  • 8
  • +1 The only thing the reciver knows is the end of the stream. If you want it to know about "messages" you need to add a protocol to do this. e.g. send a 4 byte length before each message so it knows how much to reads. – Peter Lawrey Dec 18 '13 at 20:20
  • Now I firstly send a number of lines of file, then lines themselves and client read as many times as the number says. Thanks – Stepan Tuhacek Dec 22 '13 at 13:35
0

You have two problems with your reader. You assume you will always read a full buffer. You cannot assume this unless you only read one byte at a time. You also assume you will always read whole multi-byte characters, this is unlikely to be true unless you never use multi-byte characters.

Since you are writing text I suggest you send new lines between messages and read the stream as text.

BufferedReader br = new BufferedReader(new InputStreamReader(
                        Client.getCl().getInputStream(), "UTF-8"));
for(String line; (line = br.readLine()) != null; ) {
    // process a whole line of text at once. e.g.
    System.out.println(line);
}

This will decode the text, read whole lines and handle any multi-byte characters.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130