我有一个简单的C服务器和简单的Java客户端。客户端从键盘获取输入并将其发送到服务器。服务器打印并将其发回。但它只是第一次有效,可能是什么问题?
主:
package test;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Client cli = new Client();
cli.connect();
while(sc.hasNextLine()) {
cli.send(sc.nextLine());
System.out.println(cli.rec());
}
}
}
客户端:
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
Socket socket;
OutputStreamWriter out;
BufferedReader in;
public void connect() {
try {
socket = new Socket("localhost", 50001);
socket.setSoTimeout(5000);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out = new OutputStreamWriter(socket.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void send(String message) {
try {
this.out.write(message + "\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.out.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String rec() {
try {
return in.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
}
服务器:
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#define MY_PORT 50001
#define MAXBUF 1024
int main(int Count, char *Strings[])
{ int sockfd;
struct sockaddr_in self;
char buffer[MAXBUF];
int clientfd;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
int yes = 1;
/*---Create streaming socket---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("Socket");
exit(errno);
}
/*---Initialize address/port structure---*/
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == 0)
{
printf("Socket options was set.\n"); //TODO
}
else
{
printf("Set socket options failure.\n"); //TODO
}
/*---Assign a port number to the socket---*/
if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
{
perror("socket--bind");
exit(errno);
}
/*---Make it a "listening socket"---*/
if ( listen(sockfd, 20) != 0 )
{
perror("socket--listen");
exit(errno);
}
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
/*---Forever... ---*/
while (1)
{
memset(buffer, 0, MAXBUF);
/*---accept a connection (creating a data pipe)---*/
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
recv(clientfd, buffer, MAXBUF, 0);
printf("Server got: %s", buffer);
//sprintf(buffer, "%s\r\n", buffer);
/*---Echo back anything sent---*/
printf("sending...\n");
int n = send(clientfd, buffer, MAXBUF, 0);
printf("sent: %d\n", n);
}
/*---Close data connection---*/
close(clientfd);
/*---Clean up (should never get here!)---*/
close(sockfd);
return 0;
}
答案 0 :(得分:3)
嗯,这里是根本原因。 (如果您不想要详细信息,请跳过修复)
现在,显然发生的是java收到1024个字符作为输入。您可以在(C语言)服务器输出中看到这一点。 sent: 1024
要填写剩余的字符,它会发送ASCII值0 (这是NUL)
您可以通过删除java代码中的readLine()API并添加它来验证这一点。
StringBuilder strb = new StringBuilder();
while ((value = inputStream.read()) != -1) {
if(value != 0)
strb.append((char) value);
System.out.print(value + ":" + (char) value+",");
}
return strb.toString();
第一次请求来自服务器返回客户端,用户输入的数据后跟剩余的空值,发生以下情况
\n
或\r
个字符。所以你能看到输出。现在,当我们第二次尝试从此阅读器中读取时,它首先尝试清空旧缓冲区,直到找到(No \n
或\r
,除了所有NUL)。它将所有这些附加到StringBuilder(它在内部使用),然后将新读取的字符串附加到构建器。
如果出现此NUL字符,则附加到StringBuilder的所有字符都会在其缓冲区中消失。 (Explanation given here)您可以使用以下代码尝试此操作:
StringBuilder str = new StringBuilder().append((char)0).append("kishore");
System.out.println(str.toString()); // Output : Blank
这就是你无法看到输出的原因。因此,客户端和服务器通信没有问题。
修复:更改“C”服务器代码以发送正确的长度。
int bytes = recv(clientfd, buffer, MAXBUF, 0);
...
int n = send(clientfd, buffer, bytes, 0);
有了它,它应该有用。
答案 1 :(得分:1)
我不确定这会解决您的问题,但我认为您的accept
函数调用应该在while
循环中,因为我看到Jacajack刚评论过。
这样,每次收到连接时,循环都会生效。它应该是这样的:
示例强>:
/* Do what's in the loop every time that you accept a connection */
while (clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen))
{
memset(buffer, 0, MAXBUF);
/*---accept a connection (creating a data pipe)---*/
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
int iResult = recv(clientfd, buffer, MAXBUF, 0);
// iResult is the amount of data from recv
// Handle information and echo it back
}
此外,我认为您应该实现某种协议,验证服务器获得的消息(请参阅它确实以行结束或您希望的任何其他验证结束)指定)。
答案 2 :(得分:0)
接受必须在你的无限循环中。 它接受那里的任何新连接。所以你只接受第一个而不是其他。
听是您只做一次的最后一次通话。然后你按连接做。如果你有一些可扩展性(例如fork at accept),这也是你的方式。