Java and C++ socket: lost 1 first byte
Hi all,
I write a small socket app, the client is in Java, and the server is in C++ (Borland). They send message well on the same computer, but in the LAN network (between two computers in the local network), they have a problem: the message is lost one first byte (first character in the string). Could you tell me why, please? Any idea is highly appreciated.
Thank you in advance.
Best regards,
[421 byte] By [
Lehoanqa] at [2007-11-26 22:05:49]

# 1
You have error in your code or wrote wrong problem description here.
# 2
Let me post the code here:
Client (Java)
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
...
public class SoketClient {
...
Socket smtpSocket = null; // @jve:decl-index=0:
DataOutputStream os = null;
DataInputStream is = null; //
...
private void doConnect()
{
try
{
smtpSocket = new Socket(jTextFieldServerAddress.getText(),
Integer.valueOf((jTextFieldServerPort.getText())));
connected=1;
os = new DataOutputStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());
jTextFieldServerAddress.setEnabled(false);
jTextFieldServerPort.setEnabled(false);
jButtonConnect.setEnabled(false);
jButtonDisconnect.setEnabled(true);
jButtonSend.setEnabled(true);
jTextFieldText.setEnabled(true);
jLabelServerStatus.setText("Status: Connected");
}
catch (UnknownHostException e)
{
.......
}
private void sendText()
{
if (smtpSocket != null && os != null && is != null)
{
try
{
os.flush();
os.writeBytes("header"+jTextFieldText.getText()+"\n");
}
catch(UnknownHostException e)
{
....
}
}
else
{
System.out.print("Socket Error");
}
}
..............
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SoketClient application = new SoketClient();
application.getJFrame().setVisible(true);
}
});
}
Server (C++)
#include <Sockets.hpp>
...
TTcpServer *Sev;
TTimer *Timer1;
...
TCustomIpClient *client[100];
short countclients;
void __fastcall TForm7::Timer1Timer(TObject *Sender)
{
String txt;
char S[5];
bool W,R,E;
int i;
ListBox1->Items->Clear();
for (i=countclients; i <=countclients+2; i++)
{
client[i]= new TCustomIpClient(
}
if ( ! Sev->Active)
{
ListBox1->Items->Add("Server Not online!");
}
else
{
Sev->Select(&R,&W,&E);
ListBox1->Items->Add("Server: Read: "+BoolToStr(R)+
" Write: "+BoolToStr(W)+
" Exception: "+BoolToStr(E));
if (R==true)
{
Sev->Accept(client[countclients]);
countclients++;
}
}
for (i = 0; i < countclients; i++)
{
if (client[i])
{
if (!(client[i]->Active))
{
ListBox1->Items->Add("Client "+IntToStr(i)+" Not Active.");
}
else
{
client[i]->Select(&R,&W,&E);
ListBox1->Items->Add("Client ("+IntToStr(i)+"):Read: "+BoolToStr(R)+
" Write: "+BoolToStr(W)+
" Exception: "+BoolToStr(E)); \
if (R==true)
{
if (client[i]->ReceiveBuf(S,6)==-1)
{
client[i]->Active =false;
}
else{
txt = client[i]->Receiveln("\0");
ShowMessage("Got a message From client "+
IntToStr(i)+": \n" +txt);
}
}
}
}
...................
Something like this. The problem is that, on the same computer, they work together well, but on the different computer, they don't (lost one first byte).
Thank you for the quick reply. Please take a look at that code and give me some help. Thanks a lot.
Best regards,
# 3
(a) the client isn't sending trailing nulls which the server appears to be expecting, so the server is probably throwing away the first byte of the next message instead of the missing trailing null.
(b) the server is incorrectly written. There should only be one select.
(c) TCP doesn't lose data, so it can't possibly be the change from localhost to the LAN that causes this problem. There must be some other difference that happens at the same time.
ejpa at 2007-7-10 10:50:12 >

# 4
Thanks, ejp. I'd like to answer your questions:
>> (a) the client isn't sending trailing nulls which the server appears to be expecting, so the server is probably throwing away the first byte of the next message instead of the missing trailing null.
On same computer, they work well, sending message successully. But on different computers, once the client (Java) sends a message, the server (C++) receives 2 msg: the first msg is Null, and the next msg is lost one first byte. I think it's important to regconize the problem, isn't it? And it occurs everytime the client sends, not the first time. Moreover, the server reads "\n", not "\0" or null, so I think it's not the cause.
>> (b) the server is incorrectly written. There should only be one select.
I don't really understand what you meant. Could you explain for more, pls?
>> (c) TCP doesn't lose data, so it can't possibly be the change from localhost to the LAN that causes this problem. There must be some other difference that happens at the same time.
I agree with you about TCP. so it's strange! I'm wondering about the problem in 8bit and 16bit (Unicode) - but if it's so, we will lose a half of string, won't we? And about big vs. little endian, but I'm sending char, not int. How strange it is!
Any comment, please? Thanks a lot!
# 5
What is ReceiveBuf() here? Possible this method corrupts your data.
if (R==true)
{
if (client[i]->ReceiveBuf(S,6)==-1)
{
client[i]->Active =false;
}
else{
txt = client[i]->Receiveln("\0");
ShowMessage("Got a message From client "+
IntToStr(i)+": \n" +txt);
}
}
# 6
and what is this:
txt = client[i]->Receiveln("\0");
if the server isn't interested in trailing nulls?
More information please. When you go to the two-machine setup are you moving the Java client or the C++ server? And if you're moving the Java client, are both machines running the same JDK? and the same operating system?
You may have a default-charset problem.
The usual structure of a selecting server goes like this in Java, can't answer for your C++ socket wrapper library:
int selectCount = selector.select(timeout);
Iterator<SelectionKey> selectedKeys = selector.selectedKeys.iterator();
while (selectedKeys.hasNext())
{
SelectionKey key = selectedKeys.next();
selectedKeys.remove();
if (!key.isValid())
continue;
if (key.isAcceptable())
{
// process accept event
}
else if (key.isReadable())
{
// process read event
}
}
so in other words all channels are registered with the same selector and are processed in the same selecting loop.
ejpa at 2007-7-10 10:50:12 >

# 7
@Michael.Nazarov@sun.com:
The number "6" is the length of "header" which java client sent to the server, as you see here:
(Java)
private void sendText()
{
if (smtpSocket != null && os != null && is != null)
{
try
{
os.flush();
os.writeBytes("header"+jTextFieldText.getText()+"\n");
}
catch(UnknownHostException e)
{
....
}
}
it will skip the "header" and read the real text after that.
@ejp:
txt = client[i]->Receiveln("\0");
- it is used to read a line sending from client, this line is supposed to have a '\0' at the end. I tried to add '\0' like this os.writeBytes("header"+jTextFieldText.getText()+'\0');
and then remove '\0' - but there's no changes.
I have some PC with Windows XP SP2 and one Fedora PC. I tested around, exchanged in many cases, but it's the same.
It's hard to post all code here, so I upload it to yousendit.com. Please take a look at http://download.yousendit.com/D4160DEF06F58316. Please test by yourself and find the strange stuff. C++ Project is in Borland C++.
Thanks for your help!
# 8
Asking people to download code or review anything written in Borland C++ is miles beyond the scope of these forums, and miles beyond the effort I am prepared to put into this for nothing.
I suggest you try to write a Java test server that just handles one client, to see whether the problem is in the C++ code or the Java code.
ejpa at 2007-7-10 10:50:13 >

# 9
You don't have to use Borland IDE to open and compile the source code. Just take a look at the Unit7.cpp, around the receiving thread (timer). I don't want to post executable file, someone may think it's untrustable. You should not blame me for that reason. Because we're talking about Java and C++ communication, C++ source code should be present.
OK, I will try your way. Thank you a lot. Hope to have good news for you all soon.
Cheers,
# 10
I don't want your executable file and I don't want to look at C++ code that uses an unknown Sockets class library either. Good luck.
ejpa at 2007-7-10 10:50:13 >

# 11
@ejp: Thanks for your patience until now. I appreciate your help. And I think someone who interests about this topic does, too. Good night (your time) :-)
# 12
Yes, you should write some kind of test client and/or server and check how is it going. Or add as many debug output as you can to view all process. Or start both client and server under debugger and go through the process step by step.
# 13
Thank you. I wrote some more java server. They're all ok. So the problem may be in the C++ side. I moved to winsock32. The new problem is recv function invoked two times for each message sent from client. I tried to solve by reading each byte still end of the input stream. It seems to be OK now. I'm testing...
Thank you all! If anyone has question about this topic, we'll discuss for more.
Best regards,