C socket server, Java socket client : BLOCKING! - java

I am pasting my code for a simple socket server in C and a Java client.
I use write method sending character by character in Java. However after the chunk of characters are sent(here, 'h', 'e', 'y') , the Java client is send blocked as the C server does not reply to it :(
I am assuming there is some problem with sending a null character(from the Java write) that would stop the recv at the C side.
Any help would be greatly appreciated.
C server:
#include <stdio.h> /* standard in and output*/
#include <sys/socket.h> /* for socket() and socket functions*/
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* for close() */
int main(int argc, char *argv[]){
int sock, connected, bytes_received, true = 1;
char recv_data;
char replyBuffer[32];
struct sockaddr_in server_addr,client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2400);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 2400");
while(1){
sin_size = sizeof(client_addr);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
printf("\n Got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
while ((bytes_received = recv(connected,&recv_data,1,0)) > 0){
printf("\nrecv= %c\n", recv_data);
}
int success = 1;
sprintf(replyBuffer, "%d", success);
printf("reply buffer = %s\n", replyBuffer);
if (send(connected, replyBuffer, strlen(replyBuffer), 0) == -1)
perror("send() failed");
success = 0;
close(connected);
}
}
Java Client:
import java.net.*;
import java.io.*;
public class Client1
{
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.err.println("Usage: java Client1 <IP address> <Port number>");
System.exit(0);
}
BufferedReader in = null;
OutputStream out = null;
Socket sock = null;
try {
sock = new Socket(args[0], Integer.parseInt(args[1]));
out = sock.getOutputStream();
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String line = "hey";
String responseline = null;
char[] strArray;
strArray = line.toCharArray();
while (true) {
for( int index = 0; index < strArray.length; index++){
out.write(strArray[index]);
}
out.flush();
System.out.println("data sent " );
System.out.println("val returned"+in.readLine());
}
}
catch (IOException ioe) {
System.err.println(ioe);
}
finally {
if (in != null)
in.close();
if (out != null)
out.close();
if (sock != null)
sock.close();
}
}
}

from javadoc for BufferedReader.readLine()
Read a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
That's why it blocks (no lf, no cr, no crlf)
[edit]
You need to create an EOL indicator that the C program understands (just like readLine() in the java client. Let that indicator be '\n' (for consistency if nothing else)
In Client.java, append '\n' to your sent string.
In tst.c, test for '\n', when it's received, break from the recv() loop
[/edit]

Your assumption of the problem is correct. The recv call will always return a value greater than zero. I suggest using a special character to designate the end of the text and terminating the recv() loop when that character is read.

In my opinion there is an error of your server code.If you compile your server code on linux, there be an error. The type of sin_size should be socklen_t.
or you will see an error information "invalid conversion from int* to socklen_t"

client change to
out.write(line.getBytes());
server change to
char recv_data[32];
recv(connect,recv_data,32,0);

Related

C server an Java client socket connection. When reading message on client I see empty spaces before the actual message

I have a Server in C and a client in Java(TCP connection). After I connect them I send the first message from client then a response from the server and everything is ok at this point(client writes in the console the string received) when I send another message to the server and the server gives a response, this response is put at the end of a long String with unkown first characters. For example on the client side I see:
Send a message: type and press Enter key
HELLO
Server: HI
HELLO AGAIN
Server:
HELLO HELLO
Server:
The output on the server side is ok ( both client's and server's messages are seen)
Here is my server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 10011
int main(){
int socketfd, ret;
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
socketfd = socket(AF_INET,SOCK_STREAM,0);
if(socketfd < 0){
printf("\n error in socket creation");
return -1;
}
printf("\n Server socket is created\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(socketfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("Error in binding\n");
return -1;
}
printf("[*]Bind to port %d\n", PORT);
if(listen(socketfd, 10) == 0){
printf("Listening...\n");
}else{
printf("Error in binding\n");
}
newSocket = accept(socketfd, (struct sockaddr*)&newAddr, &addr_size);
if( newSocket < 0){
printf("No socket\n");
exit(1);
}
int size = 1024;
char buff[size];
char sbuff[size];
int n;
int reader;
memset(buff, 0, size);
memset(sbuff, 0, size);
// infinite loop for receiving and sending
for (;;) {
// read the message from client and copy it in buffer
reader = recv(newSocket, buff, 1024 * sizeof(char), 0);
if (reader == -1) {
perror("recv()");
break;
} else if (reader == 0) {
break;
} else {
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
bzero(buff, size);
n = 0;
// copy server message in the buffer
while ((sbuff[n++] = getchar()) != '\n');
// and send that buffer to client
write(newSocket, sbuff, sizeof(sbuff));
bzero(sbuff,size);
}
}
close(newSocket);
return 0;
}
and here is my client:
import java.io.*;
import java.net.*;
public class ClientJava
{
public static void main(String[] args) throws Exception
{
Socket sock = new Socket("127.0.0.1", 10011);
// reading from keyboard (keyRead object)
BufferedReader keyRead = new BufferedReader(new InputStreamReader(System.in));
// sending to client (pwrite object)
OutputStream ostream = sock.getOutputStream();
PrintWriter pwrite = new PrintWriter(ostream, true);
// receiving from server ( receiveRead object)
InputStream istream = sock.getInputStream();
BufferedReader receiveRead = new BufferedReader(new InputStreamReader(istream), 1024);
System.out.println("Send a message: type and press Enter key");
String receiveMessage, sendMessage;
while(true)
{
sendMessage = keyRead.readLine(); // keyboard reading
pwrite.println(sendMessage); // sending to server
pwrite.flush(); // flush the data
// for(int i=0; i<1024;i++){
// String s=receiveRead.read();
// receiveMessage[i]=s;
// if(s == ">") {
// return i;
// }
// }
// System.out.println(receiveMessage);
receiveMessage = receiveRead;
if((receiveMessage) != "0") //receive from server
{
System.out.println(receiveMessage); // displaying at DOS prompt
}
//removeNonAscii(receiveMessage);
//replaceUnreadable(receiveMessage);
receiveMessage = receiveMessage.substring(0,0);
}
}
private static String removeNonAscii(String s){
StringBuffer sb = new StringBuffer();
for(int i=0; i<s.length(); ++i){
if(s.charAt(i) < 128){
sb.append(s.charAt(i));
}
}
return sb.toString();
}
private static String replaceUnreadable(String s){
String clean = s.replaceAll("\\P{Print}", "");
return clean;
}
}
After debugging I found out that when receiving the message for the second time recieveMessage is full of empty characters and the actual message goes to the end of the String(so it is not visible in the console). How can I clean the String or put the message at the beginning of it? Thanks.
Solved: I used this method
private static String replaceUnreadable(String s){
String clean = s.replaceAll("\\P{Print}", "");
return clean;
}
and it worked

Trying to pass data generated in C to Java class via pipe. Pass variable is coming up blank in java instead of having data

There are 6 files/classes: mainLaptop, Send, c_app, StreamTest, make file, and ap.text.
I am trying to get the data that is processed in the c file and pass it to a variable in my java file. Following the "PIPE WITH STRINGS" section of this tutorial here: http://www.jonathanbeard.io/tutorials/CtoJava
First I open the terminal and type
1 make StreamTest
2 make c_app
3 java -cp . StreamTest
4 ./c_app
When executing, I see "JAVA SIDE!!" followed by the total, number count and average from the c process in the terminal (along with some errors due to my modifications)
Then in eclipse I run StreamTest in eclipse
Eclipse outputs this
JAVA SIDE:
[x] Sent ''Leonardo
[x] Sent ''Raphael
[x] Sent ''Donatello
[x] Sent ''Michelangelo
But I need it to output this
JAVA SIDE:
[x] Sent 'Total: 4953, Integers: 1000, Average: 4.9530'Leonardo
[x] Sent 'Total: 4953, Integers: 1000, Average: 4.9530'Raphael
[x] Sent 'Total: 4953, Integers: 1000, Average: 4.9530'Donatello
[x] Sent 'Total: 4953, Integers: 1000, Average: 4.9530'Michelangelo
Here is the c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#define DEBUG 0
#define BUFFER 4096
//open ap.txt for text input
static const char* exFile = "ap.txt";
static char inputBuffer[BUFFER];
int main(int argc, const char** argv)
{
FILE *fp = fopen(exFile,"r");
/*check and see if the pointer is null in otherwords see if the memory
location refered to by fp is set...no memory location should be zero
if you want to reference it
Here are some good ways to do this other than the way I did it below:
if(!fp) {do error}
if(fp == NULL) {do error}
and then there's the way I did it below
*/
if(fp == 0){
fprintf(stderr,"Null pointer exception, check file name.\n");
exit(-1);
}
//check and see if an error occured during open
const int err = ferror(fp);
if(err != 0){
/* void perror(const char* err) returns specific error message to string attached. */
const char* errMessage = strcat("Something bad happened while opening file ",exFile);
perror(errMessage);
}
#if (DEBUG == 1)
else{
fprintf(stderr,"Success opening file!!\n");
}
#endif
setbuf(fp,inputBuffer); //set a buffer for input
uint64_t *num = (uint64_t*) malloc(sizeof(uint64_t));
uint64_t total = 0;
uint64_t n = 0;
//test for eof
/*
feof(*fp) - returns a boolean true if at end of file and false otherwise
*/
while(!feof(fp)){
//fscanf returns the number of items it converted using %llu, if it's not equal to 1 we don't want to continue
if(fscanf(fp,"%"PRIu64"",num)!=1)
break; //you could do a lot of stuff here as far as error handling but basically something bad has happened
total+= *num; //add to total the value at memory location num
n++;
#if (DEBUG == 1)
fprintf(stderr,"line number %"PRIu64"\n",n);
#endif
}
free(num);
const double average = (double) total / (double) n;
//close the inputfile
fclose(fp);
//declare our outputfile, use a pipe in this case to a java process
//we open a java process for this process to pipe to, also it is
//technically a bi-directional pipe so we can use any of the modifiers
//like r/w/r+/etc
static const char* outFile = "java -cp . StreamTest";
FILE *fp_out = popen(outFile,"w");
//setbuf(fp_out,outputBuffer);
fprintf(fp_out,"Total: %"PRIu64", Integers: %"PRIu64", Average:
%.4f\n",total,n,average);
/*
int fflush(*fp) pushes any data in the buffer to be written
the return value returns 0 if successful or !=0 if an error
occurs....remember return values in C often equal exceptions
*/
fflush(fp_out);
/* int */
fclose(fp_out);
return 1;
}
Here is the make file
CC ?=gcc
JCC ?= javac
FLAGS ?= -Wall -O2
JFLAGS ?= -g -verbose
all: c_app StreamTest
c_app: c_app.c
$(CC) $(FLAGS) -o c_app c_app.c
StreamTest: StreamTest.java
$(JCC) $(JFLAGS) StreamTest.java $(LIBS)
clean:
rm -f c_app StreamTest.class
The ap.text file is just a bunch of numbers
StreamTest
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
public class StreamTest
{
private static final int buffer = 4096;
public static void main(String[] args) throws Exception
{
String pass=null;
InputStream is = null;
BufferedInputStream bis = null;
try
{
bis = new BufferedInputStream(System.in,buffer);
StringBuilder sb = new StringBuilder();
//sb.append((char)bis.read());
while(bis.available() > 0){
sb.append((char)bis.read());
}
pass = sb.toString();
System.out.println("JAVA SIDE: "+pass);
bis.close();
}
catch(IOException ex)
{
}
finally
{
}
//pass = "hi";
mainLaptop.main(pass);
}
}
Here is my mainLaptop class that is invoked in my StreamTest class.
public class mainLaptop
{
public static void main(String arg) throws Exception
{
//Timing out? change the IP!
String ip="192.168.137.127";
String Pi1Q1="Leonardo";
String Pi1Q2="Raphael";
String Pi2Q3="Donatello";
String Pi2Q4="Michelangelo";
String pass=arg;
Send.send(ip, Pi1Q1, pass);
Send.send(ip, Pi1Q2, pass);
Send.send(ip, Pi2Q3, pass);
Send.send(ip, Pi2Q4, pass);
/* Recv.recv(ip, Pi1Q1);
Recv.recv(ip, Pi1Q2);
Recv.recv(ip, Pi2Q3);
Recv.recv(ip, Pi2Q4);*/
}
}
Here is my Send code that is being invoked in my mainLaptop class
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Send
{
public static void send(String ip, String Q, String pass) throws
Exception
{
ConnectionFactory factory = new ConnectionFactory();
//set connection info
factory.setHost(ip);
factory.setUsername("test");
factory.setPassword("test");
//create connection
Connection connection = factory.newConnection();
//create channel
Channel channel = connection.createChannel();
//publish message
// int a = 1;
//while (a!=0)
{
channel.queueDeclare(Q, false, false, false, null);
//for(int i=1; i<=2; i++)
{
//String message = pass;
channel.basicPublish("", Q, null, pass.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + pass + "'" + Q);
}
//a--;
}
//SHUT IT ALL DOWN!
channel.close();
connection.close();
}
}
Updated Stream Test with some of #EJP's suggested edits
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
public class StreamTest{
private static final int buffer = 4096;
static String pass;
public static void main(String[] args)
{
InputStream is = null;
BufferedInputStream bis = null;
BufferedReader bir = null;
try
{
bis = new BufferedInputStream(System.in,buffer);
StringBuilder sb = new StringBuilder();
while ((bir.readLine()) != null)
{
// Do something here. Who knows
}
/*while(bis.available() > 0){
sb.append((char)bis.read());
}*/
/*int b;
while ((b = bis.read()) != -1)
{
// do something with 'b'
sb.append((char)b);
}*/
pass=sb.toString();
System.out.println("JAVA SIDE: "+pass);
bir.close();
bis.close();
}
catch(IOException ex)
{
}
finally{
}
try {
mainLaptop.main(pass);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
available() is not a test for end of stream. See the Javadoc. Get rid of it, and terminate the read loop when read() returns -1, or use BufferedReader.readLine() and terminate when it returns null.
And don't ignore exceptions.
EDIT To drive the point home, your revised loop should read:
int b;
while ((b = bis.read()) != -1)
{
sb.append((char)b);
}
or more probably
String line;
while ((line = bufferedReader.readLine()) != null)
{
// Do something with 'line', other than merely appending it to a StringBuffer
}

Reading input from C socket client to Java socket server

I have 2 socket clients and 2 socket servers, one of each in C and Java and all running on my local machine as processes.
They can all talk to each other successfully except the C socket and Java server. They connect successfully but when I type input into the C client, the enter key does not finish the message and send it to the Java server in the same manner it does when communicating with the C server.
Any insight would be greatly appreciated.
Java Server:
import java.net.*;
import java.io.*;
public class SimpleServer extends Thread
{
private ServerSocket serverSocket;
String clientmsg = "";
public SimpleServer(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run()
{
while(true)
{
try
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("Thank you for connecting to "
+ server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
}
catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}
catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = Integer.parseInt(args[0]);
try
{
Thread t = new SimpleServer(port);
t.start();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
C client:
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno;
struct sockaddr_in serv_addr;
struct hostent *server;
int n;
char buffer[256];
if (argc < 3)
{
error("ERROR, no port provided");
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
server = gethostbyname(argv[1]);
if (server == NULL)
{
error("ERROR, host not found\n");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[2]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
if (connect(sockfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
error("ERROR connecting to server");
}
printf("Enter a message for the server: ");
bzero(buffer,256);
fgets(buffer,sizeof(buffer),stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
{/
error("ERROR writing to socket");
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
printf("%s\n", buffer);
return 0;
}
I would suggest to use BufferedReader and PrintWriter as follow,
BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); // Bufferreader from socket
PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // printwriter from socket
You can simply use them as ,
in.readLine(); // read a line
out.println(); // write a line
So updated code would look like,
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream()));
System.out.println(in.readline());
PrintWriter out = new PrintWriter(server.getOutputStream());
out.println("Thank you for connecting to ");
Additionally if i'm correct this approach would fulfill line terminal conditions for both Java and C.
From the readUTF() documentation :
First, two bytes are read and used to construct an unsigned 16-bit integer in exactly the manner of the readUnsignedShort method . This integer value is called the UTF length and specifies the number of additional bytes to be read.
In your C client, you are not sending these two bytes. Of course, this is also true for writeUTF().
Data to be read by readUTF() must be sent by writeUTF(), or something that can produce the same protoco:l: see the Javadoc. As your sender is C this is not practical, so you should use a different read API, for example readLine(), with suitable adjustment at the sender.

c - client / java - server - client reading strange things

Server:
public static void getListOfFiles(String path, DataOutputStream outToClient) throws IOException
{
// Directory path here
//String path = ".";
String files;
try
{
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
String sendOver = "";
for (int i = 0; i < listOfFiles.length; i++)
{
files = listOfFiles[i].getAbsolutePath();
sendOver = sendOver + "!" + files;
}
outToClient.writeBytes(sendOver + "\n");
}
catch (Exception e)
{
outToClient.writeBytes("There was an error with the path, please try again. \n" );
}
}
public static void getDate(DataOutputStream outToClient) throws IOException
{
outToClient.writeBytes(Calendar.getInstance().getTime().toString() + '\n');
}
public static void getUsers(DataOutputStream outToClient) throws IOException
{
outToClient.writeBytes("User logged in: "+ System.getProperty("user.name") + "\n");
}
}
Client:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int sock, bytes_recieved;
char send_data[1024],recv_data[1024];
struct hostent *host;
struct sockaddr_in server_addr;
bytes_recieved = 1024;
host = gethostbyname("localhost");
sock = socket(AF_INET, SOCK_STREAM,0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3324);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr));
char *temp = '\n';
while(1)
{
printf("Enter Command...\n");
gets(send_data);
strcat(send_data, "\n");
send(sock,send_data,strlen(send_data), 0);
if(send_data[0] == 'Q' && send_data[1] == 'U' && send_data[2] == 'I' && send_data[3] == 'T')
{
printf("Quiting...");
break;
}
//printf("\nSend Data :");
recv_data[bytes_recieved] = '\0';
bytes_recieved = recv(sock,recv_data,1024,0);
//fflush(stdin);
printf("\nRecieved data = %s" , recv_data);
recv_data[bytes_recieved] = '\0';
}
}
Essentially, the server side recieves everything correctly (I have debugged it), however the client must not be reading correctly-
Here are some examples from my console on the client side:
test
Recieved data = Error wEnter Command...**<---- What The??**
Recieved data = ith command: TEST_c.dylibEnter Command... **<---- What The??**
Recieved data = Error with command: dylibEnter Command... **<---- What The??**
Recieved data = Error with command: Enter Command... **<---- What The??**
I am writing back
outToClient.writeBytes("Error with command: " + capitalizedSentence + "\n" );
When I get the above. Hopefully someone is better versed in C.
One bug (not sure is there are more):
You do:
bytes_recieved = 1024;
char send_data[1024],recv_data[1024];
recv_data[bytes_recieved] = '\0'; // <--- HERE YOU ARE WRITING OUT OF BOUNDS
bytes_recieved = recv(sock,recv_data,1024,0);
Try:
recv_data[bytes_recieved - 1] = '\0';
bytes_recieved = recv(sock,recv_data,1023,0);
Also, unless all messages are 1023 bytes long. You may have to add the \0 at the end of the string, instead of the end of buffer.
Finally, you should have a look at the manual for the usage of read. http://linux.die.net/man/2/recv.
It is possible, that you are not using the flag you intend to use. You can see a way of determining the number of bytes available in the buffer here: https://stackoverflow.com/a/3054519/828193
Hope that helps.

Why can't I send an int from java to C without waiting?

I'm having a bit of a weird problem. I'm trying to write an interface between a C client and a Java server. To this end I've written a gateway in Java (which communicates with the server using RMI). Almost everything is working, but I'm trying to return some integers from the gateway to the C client. Here's the code:
Java gateway:
import java.net.Socket;
import java.net.ServerSocket;
import java.net.MalformedURLException;
import java.io.BufferedReader;
import java.net.InetSocketAddress;
import java.io.InputStreamReader;
import java.io.DataOutputStream;
import java.lang.System;
public class hotelgw{
public static final int PORT = 4242;
public static final int BACKLOG = 5;
public static final int MAX_ARGS = 5;
public hotelgw(){
InetSocketAddress address;
ServerSocket socket = null;
try{
address = new InetSocketAddress(PORT);
socket = new ServerSocket(PORT,BACKLOG);
}catch (Exception e){
System.out.println("Error: "+e);
System.exit(1);
}
while(true){
Socket newsock = null;
try{
newsock = socket.accept();
}catch (Exception e){
System.out.println("Error: "+e);
System.exit(1);
}
BufferedReader in = null;
DataOutputStream out = null;
try{
in = new BufferedReader(new InputStreamReader(newsock.getInputStream()));
out = new DataOutputStream(newsock.getOutputStream());
}catch (Exception e){
System.out.println("Error: "+e);
System.exit(1);
}
String[] init_args = new String[MAX_ARGS];
int i = 0;
String c;
try{
while(!(c = in.readLine()).equals("end")){
System.out.printf("%s",c);
init_args[i] = c;
i++;
}
}catch (Exception e){
System.out.println("Error: "+e);
System.exit(1);
}
for(int j=0;j<init_args.length;j++){
System.out.printf("init_args[%d] = %s\n", j, init_args[j]);
}
int counter = 0;
for(int j=0;j<init_args.length;j++){
if(init_args[j] != null){
counter++;
}
}
String[] final_args = new String[counter];
for(int j=0;j<counter;j++){
final_args[j] = init_args[j];
}
if(final_args[1].equals("list")){
int[] list = hotelclient.get_list(final_args);
System.out.println("list received in hotelgw.java");
for(int j=0;j<list.length;j++){
try{
out.writeInt(list[j]);
}catch (Exception e){
System.out.println("Error writing to socket: " + e);
System.exit(1);
}
}
}
try{
in.close();
newsock.close();
}catch (Exception e){
System.out.println("Error: "+e);
System.exit(1);
}
}
}
}
C client:
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define PORT 4242
#define TYPES_OF_ROOMS 3
#define BUFFER_SIZE 64
/*Writes message to socket*/
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const int *ptr;
ptr = vptr;
nleft = n;
while(nleft>0){
if ( ((nwritten = write(fd,ptr,nleft)) <= 0)){
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
int create_socket(char* address){
struct hostent *server_address;
struct in_addr *addr;
struct sockaddr_in server_addr;
socklen_t addrlen;
char* ip;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0){
perror("Error creating socket");
exit(1);
}
server_address = gethostbyname(address);
if(server_address == NULL){
fprintf(stderr, "Server not found!\n");
exit(1);
}else{
addr = (struct in_addr*) server_address->h_addr_list[0];
}
ip = inet_ntoa(*addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(ip);
addrlen = (socklen_t) sizeof(struct sockaddr_in);
if(connect(sockfd,(struct sockaddr *) &server_addr, addrlen)){
perror("Error connecting to server");
exit(1);
}
return sockfd;
}
int main(int argc, char** argv){
int sockfd, err, i, type1=0, type2=0, type3=0;
int int_buf[TYPES_OF_ROOMS];
char string_buf[BUFFER_SIZE];
char newline = '\n';
char *end = "end";
if(argc == 1){
printf("Usage: hotelgwclient <address> {list,guests,book} [room type] [guest name]\n");
exit(1);
}
sockfd = create_socket(argv[1]);
printf("Socket created\n");
if(strcmp(argv[2], "list")==0){
if(argc != 3){
printf("Usage: hotelgwclient <address> list\n");
exit(1);
}
printf("list initiated\n");
writen(sockfd, argv[1], strlen(argv[1]));
writen(sockfd, &newline , sizeof(newline));
writen(sockfd, argv[2], strlen(argv[2]));
writen(sockfd, &newline, sizeof(newline));
writen(sockfd, end, strlen(end));
writen(sockfd, &newline, sizeof(newline));
printf("Written to socket\n");
err = read(sockfd, &type1, sizeof(int));
err = read(sockfd, &type2, sizeof(int));
err = read(sockfd, &type3, sizeof(int));
printf("Read from socket\n");
if(err<0){
perror("Error reading from socket");
exit(1);
}
/*
for(i=0;i<TYPES_OF_ROOMS;i++){
printf("%d\t",int_buf[i]);
}
*/
type1 = htonl(type1);
type2 = htonl(type2);
type3 = htonl(type3);
printf("%d\t",type1);
printf("%d\t",type2);
printf("%d\t",type3);
printf("\n");
return 0;
}
printf("Command not recognized.\nUsage: hotelgwclient <address> {list,guests,book} [room type] [guest name]\n");
exit(1);
}
(N.B. I know it's messy, I'mma clean it up when it works :) ).
The problem is that whenever I call the list method, and C tries to read the respons (three ints) it will only read one byte, not four. This is fixed if I add a sleep() call before reading from the sockets. Does anybody know what's happening and what I should do to fix it?!
Thanks!
I suspect the problem is that you are assuming you will read as much data as you want when the minimum is always 1 (even in Java)
Why you are getting one byte before the others is that you are using DataOutputStream without a BufferedOutputStream so it is sending one byte at a time. It might be tempting to use this workaround but it just hides the underlying problem that you need to be able to read one byte at a time correctly as this is always a possibility.
Its valid for read to return fewer bytes that you requested. From its man page:
Return ValueOn success, the number of bytes read is returned... It
is not an error if this number is smaller than the number of bytes
requested; this may happen
You'll need to call read in a loop until the expected number of bytes or an error have been returned:
unsigned char* p = &type1;
int expected = sizeof(int);
while (expected > 0) {
err = read(sockfd, p, expected);
if (err < 0) {
break;
}
p += err;
expected -= err;
}
When there are blocking calls involved and must act parallely, you gotta add threads for each task(such as one for reading and another for writing) so that they don't block the execution.
Also put everything received in a buffer and try to parse from there on. Implement threads with pthread api.

Categories