Reputation: 43
I have a problem with sockets between Java and C. I have a C program that creates a socket and starts listening. The Java client does it's work and under certain circumstances opens a socket and writes to it and tries to read from it but this blocks.
Heres the socket part of the C program:
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
char wbuffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
cout << "ERROR opening socket" << endl;
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 23456;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
cout << "Couldn't set socket params!" << endl;
int so = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
while(so < 0) {
cout << "ERROR on binding" << endl;
sleep(1);
so = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
cout << "ERROR on accept" << endl;
bzero(buffer,256);
//cout << "Socket created!" << endl;
n = read(newsockfd,buffer,255);
if (n < 0)
cout << "Error reading from socket" << endl;
if (strcmp(buffer, "power\n") == 0) {
// Do stuff
strcpy(wbuffer, "off\n");
}
//sleep(1);
n = write(newsockfd,wbuffer,strlen(wbuffer));
if (n < 0)
cout << "ERROR writing to socket" << endl;
}
//cout << "message: " << buffer << endl;
close(newsockfd);
close(sockfd);
And the Java side:
Socket socket3 = new Socket("localhost", 23456);
PrintWriter out3 = new PrintWriter(socket3.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket3.getInputStream()));
out3.write("power" + "\n");
//String status = in.readLine();
log.debug("Wrote power");
StringBuffer buffer = new StringBuffer();
while (true) {
int ch = in.read();
log.debug("in.read()");
if ((ch < 0) || (ch == '\n')) {
break;
}
buffer.append((char) ch);
}
String status = buffer.toString();
out3.close();
in.close();
socket3.close();
The writing works, I have done some debugging and it's the reading, specifically in.read(), that is the last thing done.
I am probably missing something on the Java side, because a C test client reads the output nicely.
Hopefully someone has some ideas how to get this working, I'm open to any solutions.
Upvotes: 0
Views: 379
Reputation: 43
Turns out that the problem wasn't actually in the reading part but in the writing. I had forgotten to flush the output so it hadn't actually started reading or was there anything to read for that matter. After adding the flush the reading worked just fine, I could even use readline() to make the code simpler.
The other cases where I only wrote to the socket worked because flush is called when closing the stream, this was throwing me off.
The C-code is nasty and I need to clean it up and actually handle the exceptions.
Thanks for everyone for helping me anyway, without the answers it would have taken a lot longer to find my mistake.
Upvotes: 1
Reputation: 84189
Your C++ code is pretty horrible. Consider what would happen in case read(2)
returns less then 6
. And just in general:
n = read(newsockfd,buffer,255);
if (n < 0)
cout << "Error reading from socket" << endl;
// continuing processing after an error - BAD
// not paying attention to n - BAD
if (strcmp(buffer, "power\n") == 0) {
// Do stuff
strcpy(wbuffer, "off\n");
}
// potentially writing zero bytes here - BAD
n = write(newsockfd,wbuffer,strlen(wbuffer));
if (n < 0)
cout << "ERROR writing to socket" << endl;
} // WHERE DID THIS PAREN COME FROM?
So fix those problems. Check with tcpdump(1)
or wireshark what you get on the wire. Print out your input on both sides. You'll probably see that you assumptions are off somewhere.
Upvotes: 2
Reputation: 1382
Maybe the problem is you're reading an Integer:
int ch = in.read()
Have you tried changing it for:
char ch = in.read()
Or having the integer cast to a char before comparing:
if((char) ch == '\n' || ch < 0)
I can't think of anything else right now...
Upvotes: 0