I make a java socket server and c socket client, here are the code
Java Socket Server:
int Send_Request(String s) {
try {
os = socket.getOutputStream();
os.write(s.getBytes());
os.flush();
Log.d(tag,"Data = " + s);
return 0;
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e(tag,"Send Request Error");
return -1;
}
C socket client:
void* recv_request()
{
int i,in;
char buf[1024];
while(1)
{
if ( ( in = read(sockfd, buf, strlen(buf)) ) != -1 )
{
LOGD("Received = %s ...",buf);
sendServerCutText(buf);
memset(buf,0,strlen(buf));
}
}
}
The problem is .. when i send from the server, it is blocking on flush(), the c client cannot receive until there is another Send_Request called.
where is the problem??
There is a conceptual problem. You think TCP is message oriented (sending messages with specified length). It's not like that, it is only providing a stream of bytes.
For sending a message with a specified length a common technique is to send first the length (encoded in fixed length, eg 4 byte integer in network byte order) and then the actual message.
There's also an implementation problem, the 3rd argument for read should be the maximum read length, which should be 1024, executing strlen on a non-initialized local char array is clearly undefined-behaviour.
Related
I am trying to make two processes communicate through local sockets: a Python server and a Java client. The data I want to pass between both consists of the bytes of a Protobuf object, with variable size. I want the connection to remain open and be used until the end of the program, because I'm passing a lot of objects that need to be processed.
Because Protobuf objects have variable size, I am sending the size of the message/response before sending the true message/response containing the object.
Currently, I am using a TCPServer from the socketserver library on the Python side. I have the following handler implemented:
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def recv_all(self, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = self.request.recv(n - len(data))
if not packet:
return None
data += packet
return data
def handle(self):
logger.debug("Beginning of handle cycle for client: {}.".format(self.client_address))
while True:
if True: # please disregard this if condition
# Receive 4 bytes (1 int) denoting the size of the message
data_length_bytes: bytes = self.recv_all(4)
logger.debug('Received data_length: {}'.format(data_length_bytes))
# If recv read an empty request b'', then client has closed the connection
if not data_length_bytes:
break
data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')
data: bytes = self.recv_all(data_length).strip()
response: bytes = data.upper()
# Send length of response first
self.request.sendall(len(response).to_bytes(4, byteorder='big'))
# Send response
self.request.sendall(response)
logger.debug(
'Sent response to: {}. Size of response: {} bytes. Response: {}.'.format(self.client_address,
len(response),
response))
logger.debug("End of handle cycle for client: {}.".format(self.client_address))
And the following client:
class SocketClient
{
private static Socket socket;
private int port;
private DataOutputStream out;
private DataInputStream in;
SocketClient(int port)
{
this.port = port;
this.createSocket();
}
private void createSocket() {
InetAddress address;
try {
address = InetAddress.getByName("localhost");
socket = new Socket(address, port);
this.out = new DataOutputStream(socket.getOutputStream());
this.in = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] sendMessageAndReceiveResponse(byte[] messageToSend){
try {
if(true) { // again, please disregard this condition
//Send the size of the message to the server
this.out.writeInt(messageToSend.length);
out.flush();
this.out.write(messageToSend);
out.flush();
//Get the response message from the server
int length = in.readInt(); // read length of incoming message
byte[] buffer = null;
if(length>=0) {
buffer = new byte[length];
in.readFully(buffer, 0, buffer.length); // read the message
}
return buffer;
}
}
catch (ConnectException exception) {
System.out.println("ATTENTION! Could not connect to socket. Nothing was retrieved from the Python module.");
exception.printStackTrace();
return null;
}
catch (Exception exception)
{
exception.printStackTrace();
return null;
}
}
void close(){
//Closing the socket
try
{
in.close();
out.close();
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
I run the following experiment after starting the Python server:
SocketClient socketClient = new SocketClient(5000);
byte[] response;
// Case 1
response = socketClient.sendMessageAndReceiveResponse("12345678".getBytes());
System.out.println(new String(response));
// Case 2
response = socketClient.sendMessageAndReceiveResponse("123456781".getBytes());
System.out.println(new String(response));
// Case 3
response = socketClient.sendMessageAndReceiveResponse("12345678123456781".getBytes());
System.out.println(new String(response));
socketClient.close();
Case 1 and case 3 work well. However, when I run case 2, on the Python server side, I get the following log:
DEBUG -- [handle()] Received data_length: b'\x00\x00\x00\t' # The '\t' shouldn't be here. A '\x09' should.
And then the server throws and exception and exits the connection. This happens with every string with 8 < length < 14. What am I doing wrong, and is there an easier way to achieve what I want?
I figured out why I was having problems with messages of 8 < length < 14.
I was getting the \t character when length was equal to 9. I noticed that if I changed the length to 10, it would become \n. And to 13, \r. I realized that there wasn't any \t magically appearing. Python was for some reason converting \x09 to \t, because the horizontal tab character \t has an ASCII code equal to 9!
And when I applied the strip() function in this line:
data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')
, Python deleted my \t, which was actually my \x09. My problem was logging the value before stripping it, and so I took a long time to figure out my mistake.
Therefore the solution was to simply not use strip(). I leave here my current working code (at least for my tests), for someone to use:
Python server handler:
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def recv_all(self, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = self.request.recv(n - len(data))
if not packet:
return None
data += packet
return data
def handle(self):
while True:
data_length_bytes: bytes = self.recv_all(4)
# If recv read an empty request b'', then client has closed the connection
if not data_length_bytes:
break
# DON'T DO strip() ON THE DATA_LENGTH PACKET. It might delete what Python thinks is whitespace but
# it actually is a byte that makes part of the integer.
data_length: int = int.from_bytes(data_length_bytes, byteorder='big')
# Don't do strip() on data either (be sure to check if there is some error if you do use)
data: bytes = self.recv_all(data_length)
response: bytes = data.upper()
self.request.sendall(len(response).to_bytes(4, byteorder='big'))
self.request.sendall(response)
The Java client remained the same, but without that if(true) condition that I was using for debug reasons.
I'm trying to implement a communication system with an automatic repeat request strategy. I use three classes: Transmitter, Channel, Receiver. I have a maximum number of byte for message (window). But when I receive the byte sent, sometimes I receive less bytes than window. Why?
My code is this:
Transmitter
int n = 0;
int remaining, length;
while (n<channelBytes.length) {
remaining = channelBytes.length-n;
length = (remaining<window)? remaining : window;
outputStream.write(channelBytes,n,length);
// wait for the ack
byte[] b = new byte[4];
channel.socket().setSoTimeout(2000);
inputStream.read(b);
n += ByteBuffer.wrap(b).getInt();
}
Channel
bytes = new byte[SystemModel.WINDOW];
while(true) {
// receive from Tx
upInputStream.read(bytes);
// insert channel error
insertError(bytes);
Thread.sleep(propagationDelay + transmissionDelay);
// send bytes to Rx
downOutputStream.write(bytes);
// wait for the ack from Rx
clientChannelDown.socket().setSoTimeout(2000);
byte[] ack = new byte[4];
downInputStream.read(ack);
// send ack to Tx
upOutputStream.write(ByteBuffer.allocate(4).put(ack).array());
}
Receiver
byte[] b = new byte[SystemModel.WINDOW];
while (true) {
try {
int received = inputStream.read(b);
channelCoding.decodePartially(b);
}catch (SocketTimeoutException te){
break;
} catch (IOException e) {
e.printStackTrace();
} catch (DataFormatException e) {
// send ack
int ack = Integer.parseInt(e.getMessage());
try {
outputStream.write(ByteBuffer.allocate(4).putInt(ack).array());
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
In the Receiver, the array of bytes "b" is not always the length of the window.
Invalid code. See the Javadoc. InputStream.read(byte[] [,...]) isn't obliged to transfer more than one byte, and it is never valid to call it without storing the result into a variable. If you're expecting more than one byte, you have to loop, or use DataInputStream.readFully().
The canonical way to copy streams in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
For ByteBuffers with Channels it is as follows:
while (in.read(buffer) > 0 || buffer.position() > 0)
{
buffer.flip();
out.write(buffer);
buffer.compact();
}
If you code correctly there is no need to insert sleeps into network code.
E&OE
I'm trying to write a program which acts as a server that will read bytes from a client that is written in PHP - sends request via socket (which i cannot recode due to policy) Here is the server code:
The server runs in: Red Hat Enterprise Linux Server release 6.2 (Santiago)
public void run() {
try {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(0);
while(!isInterrupted) {
try {
Socket server = serverSocket.accept();
LOG.info("Request received from : " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
// DataInputStream in = new DataInputStream(
// new BufferedInputStream(server.getInputStream(), 10000));
byte[] bytes = new byte[10000];
int byteDupLength = in.read(t_bytes);
// in.readFully(bytes); // I tried this but to no avail
// int byteDupLength = bytes.length;
LOG.info(byteDupLength);
byte[] byteDup = new byte[byteDupLength];
System.arraycopy(bytes, 4, byteDup, 0, byteDupLength);
// FOR INFORMATION ONLY
/*for (byte b : byteDup){
LOG.info(b);
}*/
ByteBuffer buffer = ByteBuffer.wrap(byteDup);
LOG.info(buffer);
forwardRequest(byteDup);
server.close();
}
catch(SocketTimeoutException s) {
LOG.error("Socket timed out!", s);
break;
}
catch(IOException e)
{
LOG.error("IOException:", e);
break;
}
}
}
catch (IOException ex) {
LOG.error("Server socket is null", ex);
}
LOG.fatal("ReceiverEngine interrupted!");
}
I encountered a problem when the client sends request consisting of 4948 bytes. The only bytes the server can read is 2090.
Another thing that seems a mystery to me is that, when I run the server via Netbeans in my local (which is a Windows 7 Pro), it works as expected. I dont know what is wrong. Please help.. :)
Thanks!
TCP is a byte stream protocol.
The read() method isn't guaranteed to fill the buffer.
Therefore if you don't receive the expected number of bytes in a single read, you have to loop until you do receive them.
readFully() would have worked if the buffer size agreed with the size of what was sent. In your case you specified a buffer of 10,000 bytes, which weren't sent, so it would have blocked waiting for the other 10000-4948 bytes.
I am stuck with the following problem. I have created a connection to a remote echo server. The following method is used for receiving the bytes received from the server:
public byte[] receive() {
byte[] resultBuff = new byte[0];
byte[] buff = new byte[4096];
try {
InputStream in = socket.getInputStream();
int k = -1;
while((k = in.read(buff, 0, buff.length)) != -1) {
System.out.println(k);
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
String test = new String(resultBuff);
System.out.println(test);
}
System.out.println(resultBuff.length + " bytes read.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultBuff;
}
I am able to get the following response from the server:
Connection to MSRG Echo server established
The problem is that the loop gets stuck at the second execution on in.read(). I understand that this is due the the server not sending any EOF info and the like.
I am not sure which of the following two solutions is correct and in which way to implement it:
Each message coming from the server will be read by a new execution of the receive() method. How do I prevent the in.read() method from blocking?
The loop inside the receive() method should be kept alive until application exit. This means that my implementation is currently using in.read() wrong. In which way should this be implemented.
The key to this question is your use of the word 'message'. There are no messages in TCP, only a byte stream. If you want messages you must implement them yourself: read a byte at a time until you have a complete message, process it, rinse and repeat. You can amortize the cost of the single-byte reads by using a BufferedInputStream.
But there are no messages in an echo server. Your read and accumulate strategy is therefore inappropriate. Just echo immediately whatever you received.
I have a big issue with my java client.
Server: perl, with IO::Socket;
$n is the socket
sub listen{
while(1){
my $n = $_[0]->accept();
my $thread;
my $thread2;
$thread = threads->create('talk', $n);
$thread2 = threads->create('recu', $n);
}
When a client send a message to the server
sub talk{
my $n = $_[0];
while(<$n>){
print $n $_;
}
In 'talk' the server send the client message back to the client
Client: Java, in a Thread
I send a byte array ->
static DataOutputStream os;
...
public static void handleMsg(byte [] b){
try {
os.write(b);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
->
<pre><code>
byte[] buff = new byte[]{10,4};
ThreadListen.handleMsg(buff);
</code></pre>
I receive in the run() method only the first byte in the array (10)
<pre><code>
public void run(){
DataInputStream in = null;
try{
in = new DataInputStream(s.getInputStream());
} catch (IOException e) {
System.out.println("in or out failed");
System.exit(-1);
}
while(true){
try{
byte[] buff = new byte[6];
int b = in.read(buff, 0, buff.length);
}catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
If I try to send
byte[] buff = new byte[]{50,4};
ThreadListen.handleMsg(buff);
I receive nothing!!!
Did i missed something, I assume that if I send
byte[] buff = new byte[]{50,4};
I should receive 50,4 :)
Thanks,
Your Perl code is doing <$n> so it's fetching data line-by-line. since 10 is the line-feed character, receiving a {10,4} sequence means it gets an empty line (which it prints back) and then a character 4. Even if it receives that (some debug messages in the Perl code would help), the print back to the socket may not complete if the socket is block-buffered (likely the default) without flushing the socket filehandle.
You may want to use read explicitly (instead of readline implicitly, which as the name suggests reads up to the end of the line, or EOF) to read from the socket.