Java Socket 프로그래밍에 관한 최근의 곤경이 지금 당장 3 일간 당황합니다. 나는 클라이언트에서 서버로 바이트를 전송하기 위해 NIO ByteBuffer와 Channel을 사용한다. 필자는 클라이언트가 두 개의 파일을 순서대로 전송하도록하여 코드를 테스트합니다. 첫 번째 파일은 항상 도착하지만 두 번째 파일은 항상 손실됩니다. 나는 tcpdump를했고 특정 주소와 포트에서 트래픽을 보았지만 pcap의 파일을 해독 할 수 없었다 (pcap 파일의 모든 구문을 읽는 방법을 이해함).Java Socket.read (ByteBuffer dst) 바이트가 없습니다.
어떻게 든 socketchannel.read (bytebuffer)는 두 번째 파일의 바이트를 읽지 않습니다. 첫 번째 파일은 괜찮습니다. 읽기 명령을 통과하고 파일을 수신하고 응답합니다. 두 번째 파일은 읽기 명령 및 응답에 적합합니다. socketchannel.read에 -1을받는 파일이 없습니다. 이것이 문제입니다.
도와주세요. 이것은 정말로 미친 문제입니다. 여기
public class ServerMain
{
public static void main(String[] args)
{
ServerSocketChannel listener = null;
ServerSocket serverMain = null;
try
{
listener = ServerSocketChannel.open();
serverMain = listener.socket();
serverMain.setReuseAddress(true);
serverMain.bind(new InetSocketAddress("192.168.1.12",9999));
while (true)
{
new ServersThread(serverMain.accept()).start();
}
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
finally
{
try
{
listener.close();
}
catch (IOException e)
{
logger.error("IOException ", e);
e.printStackTrace(System.err);
}
}
}
}
:
public class ServersThread implements Runnable
{
private Socket socket;
public ServersThread(Socket socket)
{
this();
this.socket = socket;
}
public void run()
{
try
{
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
PrintStream ps = new PrintStream(socket.getOutputStream(), true);
String orderFromClient = br.readLine(); // first read command from client
String filename = orderFromClient.split(":")[0]
long fileSize = Long.parseLong(orderFromClient.split(":")[1]);
File destFile = new File(filename);
destFile.setReadable(true);
destFile.setWritable(true);
FileOutputStream inFile = new FileOutputStream(destFile);
FileChannel inChannel = inFile.getChannel();
SocketChannel sc = socket.getChannel();
ByteBuffer dst = ByteBuffer.allocate(65536);
dst.clear();
// this receiving binary file part that is questionable.
// it always run okay for the first file
// the second file is created but always has size 0
// The second file will enter into while-loop start and end but it won't enter sc.read(dst)
logger.debug(AUDIT,"while-loop start");
start = System.currentTimeMillis();
while (sc.read(dst) != -1)
{
dst.flip();
logger.debug(AUDIT,"dst flip and ask remaining: {} at position {}",dst.hasRemaining(),dst.position());
while (dst.hasRemaining())
{
temp = inChannel.write(dst);
curnset += temp;
logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp, fileSize);
}
dst.clear();
}
end = System.currentTimeMillis();
logger.debug(AUDIT,"while-loop end");
if (curnset == fileSize)
ps.println("SUCCESS");
else
ps.println("FAIL");
}
catch(Exception e)
{
e.printStackTrace(System.err);
logger.error("Exception ",e);
}
finally
{
try
{
inChannel.close();
inFile.close();
sc.close();
ps.close();
isr.close();
br.close();
socket.close();
}
catch(IOException e)
{ }
}
}
}
가있는 ServerThread가 ServersThread에 유일한 serversocket.accept()를 통과 다른 클래스 ServerMain (소켓 socket) 여기서
의해 실행 가능한 것을 되 호출을 구현하는 ServerMain 클래스 클라이언트 클래스입니다
public class ClientCallable
{
public static void process(String serverAddr,int serverPort,File file,String command)
{
SocketChannel sc = null;
PrintStream ps = null;
BufferedReader br = null;
int timeout = 10 * 1000;
try
{
sc = SocketChannel.open();
sc.configureBlocking(true);
if (!sc.connect(new InetSocketAddress(serverAddr, serverPort)))
return ClientMain.ERROR_UNABLE_TO_CONNECT;
sc.socket().setSoTimeout(timeout);
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
return;
}
long maxCount = 8192 * 1024;
long curnset = 0l;
long temp = 0l;
long filesize = 0l;
long startTime = 0l;
long endTime = 0l;
String serverResp = null;
FileInputStream fis = null;
FileChannel fc = null;
try
{
ps = new PrintStream(sc.socket().getOutputStream());
br = new BufferedReader(new InputStreamReader(sc.socket()
.getInputStream()));
fis = new FileInputStream(file);
fc = fis.getChannel();
filesize = fc.size();
// send command to server
ps.print(command);
// send binary file
ByteBuffer dst = ByteBuffer.allocate(65536);
dst.clear();
startTime = System.currentTimeMillis();
while (fc.read(dst) != -1)
{
dst.flip();
while (dst.hasRemaining())
{
temp = sc.write(dst);
curnset += temp;
logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp,
filesize);
}
dst.clear();
}
sc.shutdownOutput();
endTime = System.currentTimeMillis();
// read server respond
serverResp = br.readLine();
logger.debug(AUDIT,"server responds {}",serverResp);
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
try
{
if (fis != null)
fis.close();
if (fc != null)
fc.close();
if (ps != null)
ps.close();
if (br != null)
br.close();
if (sc != null)
sc.close();
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
}
public static void main(String[] args)
{
String serverAddr = "192.168.1.12"
int serverPort = 9999;
File file1 = new File("file1.fpt");
File file2 = new File("file2.fpt");
String command = "somecommandtoserver";
process(serverAddr,serverPort,file1,command);
process(serverAddr,serverPort,file2,command);
}
}
클라이언트가 데이터를 보내고 서버가 계획대로 바이트를 수신했음을 tcpdump 및 wireshark를 사용하여 확인했습니다. 나는 wireshark와 pcap 파일의 ACK, PSH ACK, SYN, FIN ACK를 연구했다. 그러나 자바의 수준에서 sc.read (dst)! = 1 여전히 일어나고 있습니다! 매우 당혹 스럽네! 누구 제안? 나는 지금 재치있는 끝이다. – Spring