我创建了一个简单的Java客户端和一个c ++服务器。我正在尝试将一些数据从客户端传输到服务器。问题是,当服务器接收到数据时,它会显示一些错误的符号,并且当服务器向Java客户端返回一些响应时,我会再次看到这些错误的符号。您能帮我解决这个问题吗?。
java客户端
public Client(String host, int port) {
try {
String serverHostname = new String(host);
System.out.println("Connecting to host " + serverHostname + " on port " + port + ".");
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket(serverHostname, port);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Unknown host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Unable to get streams from server");
System.exit(1);
}
/** {@link UnknownHost} object used to read from console */
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print("client: ");
String userInput = stdIn.readLine();
/** Exit on 'q' char sent */
if ("q".equals(userInput)) {
break;
}
out.println(userInput);
System.out.println("server: " + in.readLine());
}
/** Closing all the resources */
out.close();
in.close();
stdIn.close();
echoSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
c ++服务器
int main()
{
SOCKET ConSock;
SOCKET ListenSock;
SOCKADDR_IN address;
int addsize = sizeof(address);
long ok;
char MESSAGE[200];
WSAData WSD;
WORD DllVersion = MAKEWORD(2, 1);
ok = WSAStartup(DllVersion, &WSD);
ConSock = socket(AF_INET,SOCK_STREAM,NULL);
address.sin_addr.s_addr = inet_addr("10.64.15.3");
address.sin_family = AF_INET;
address.sin_port = htons(10102);
ListenSock = socket(AF_INET,SOCK_STREAM,NULL);
bind(ListenSock,(SOCKADDR*)&address,sizeof(address));
listen(ListenSock,SOMAXCONN);
cout<<"Waiting for connection\n";
while(1)
{
if(ConSock = accept(ListenSock,(SOCKADDR*)&address,&addsize))
{
ok = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);
string msg;
msg = MESSAGE;
cout<<"Client says:\t"<<msg;
string reply;
cout<<"\nEnter reply:";
cin>>reply;
const char* rep = reply.c_str();
ok = send(ConSock,rep,1024,NULL);
}
}
}
这是我从客户端获得的输入的图片: c++ server image
答案 0 :(得分:0)
Java字符是两个字节。如果您在出入途中对其进行编码/解码,则可能会起作用(假设您也正确传达了字符串长度,我没有检查)。
StandardCharsets.ISO_8859_1.encode(chars).array() -> byte array
StandardCharsets.ISO_8859_1.decode(bytes).array() -> char array
在您开始发送文本以外的内容或选择发送unicode并在C ++端使用wstring时,下一件事将中断-Java使用网络字节顺序,C ++-主机字节顺序(与Java相反) x86)。这是原因之一。
最后一条建议-首先使它工作于Java-Java或C ++-C ++(无论您说哪种语言更好),然后切换到调试Java-C ++。
答案 1 :(得分:0)
您只是不对C ++端的任何地方进行缓冲区长度检查。
在这部分
ok = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);
string msg;
msg = MESSAGE;
您只需将所有字节分配给msg
,直到它看到0,但您再也不能将其终止了,因此它只会在内存中打印随机内容。顺便说一下,这也是潜在的缓冲区溢出。
可能更合适
auto byte_count = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);
string msg;
if(byte_cout > 0 )
{
msg.assign(MESSAGE, byte_count);
}
当您将整个缓冲区发送到此处时,会执行类似的操作:
cin>>reply;
const char* rep = reply.c_str();
ok = send(ConSock,rep,1024,NULL);
无论缓冲区大小如何,始终发送1024个字节也可能导致缓冲区溢出。
这样的事情可能会更好
cin>>reply;
ok = send(ConSock,reply.c_str(),reply.size(),NULL);
编辑:完整的程序带有一些定义明确的“消息结尾”状态,将有点像这样
Java
public Client(String host, int port) {
try {
String serverHostname = new String(host);
System.out.println("Connecting to host " + serverHostname + " on port " + port + ".");
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket(serverHostname, port);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Unknown host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Unable to get streams from server");
System.exit(1);
}
/** {@link UnknownHost} object used to read from console */
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print("client: ");
String userInput = stdIn.readLine();
/** Exit on 'q' char sent */
if ("q".equals(userInput)) {
break;
}
out.println(userInput);
//send a newline as a marker for "message is over"
out.write('\n');
System.out.println("server: " + in.readLine());
}
/** Closing all the resources */
out.close();
in.close();
stdIn.close();
echoSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
C ++方面
int main()
{
SOCKET ConSock;
SOCKET ListenSock;
SOCKADDR_IN address;
int addsize = sizeof(address);
long ok;
char MESSAGE[200];
WSAData WSD;
WORD DllVersion = MAKEWORD(2, 1);
ok = WSAStartup(DllVersion, &WSD);
ConSock = socket(AF_INET,SOCK_STREAM,NULL);
address.sin_addr.s_addr = inet_addr("10.64.15.3");
address.sin_family = AF_INET;
address.sin_port = htons(10102);
ListenSock = socket(AF_INET,SOCK_STREAM,NULL);
bind(ListenSock,(SOCKADDR*)&address,sizeof(address));
listen(ListenSock,SOMAXCONN);
cout<<"Waiting for connection\n";
while(1)
{
if(ConSock = accept(ListenSock,(SOCKADDR*)&address,&addsize))
{
string msg;
bool message_finished = false;
//read into msg until we read a newline at the end or we get an error
while(!message_finished)
{
auto length_read = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);
if(length_read > 0)
{
msg.append(MESSAGE,length_read);
message_finished = msg[msg.size()-1] == '\n';
}
else if(length_read < 0)
{
//don't continue to just endlessly loop on error
message_finished = true;
}
}
cout<<"Client says:\t"<<msg;
string reply;
cout<<"\nEnter reply:";
cin>>reply;
//append a newline at the end to mark the end of the message
reply+='\n';
ok = send(ConSock, reply.c_str(), reply.size(),NULL);
}
}
}