我正在通过套接字创建文件传输。我的客户端是Java,我的服务器是C.我能够确认客户端和服务器之间的连接,并将文件名也发送到服务器。该文件也在服务器端创建,但服务器无法获得EOF,因此卡在循环中。因此,文件传输后没有数据传输。我的相关客户端和服务器代码如下。请指导/纠正我如何实现这一目标。
C中的服务器
int connfd;
int n;
char buffer[3000];
FILE *fp;
int result;
char *message = "";
n = recv(connfd, buffer, sizeof buffer, 0); //connfd is my created socket
if ( n > 0 )
{
fprintf(stdout,"Received %d bytes\n", n);
fprintf(stdout,"Received Data: %s",buffer);
buffer[strlen(buffer)-1] = '\0';
if(strcmp(buffer, "incoming_file"))
{
fprintf(stdout, "client: incoming file");
message="send data\n";
result = send(connfd , message , strlen(message) , 0);
if(result == SOCKET_ERROR)
printf("send failed with error codfe %d\n",WSAGetLastError());
else
fprintf(stdout,"\nsent %d bytes out of %u \n",result,strlen(message));
}
else
{
fprintf(stdout,"invalid data received");
return NULL;
}
n = recv(connfd, buffer, sizeof buffer, 0);
if(n > 0)
{
fprintf(stdout, "Received %d bytes\n", n);
fprintf(stdout,"Received Data: %s",buffer);
fp = fopen(buffer, "wb");
if (fp == NULL)
{
printf("File not created!\n");
return NULL;
}
else
{
printf("Created file %s\n", buffer);
message="file created\n";
result = send(connfd , message , strlen(message) , 0);
if(result == SOCKET_ERROR)
printf("send failed with error codfe %d\n",WSAGetLastError());
else
fprintf(stdout,"\nsent %d bytes out of %u \n",result,strlen(message));
while ((n = recv(connfd, buffer, sizeof buffer, 0)) > 0)
{
fwrite(buffer, sizeof(char), n, fp);
fprintf(stdout, "Received %d bytes\n", n);
} //gets stuck in this loop
printf("\n after while"); // control never comes here
message="file uploaded\n";
result = send(connfd , message , strlen(message) , 0);
if(result == SOCKET_ERROR)
printf("send failed with error codfe %d\n",WSAGetLastError());
else
fprintf(stdout,"\nsent %d bytes out of %u \n",result,strlen(message));
}
}
else
{
fprintf(stdout,"filename not received");
}
}
else
{
fprintf(stdout,"no data received");
}
printf("client disconnected from);
getchar();
closesocket(connfd);
WSACleanup();
return 0;
}
Java客户端
File file = new File("C:/Data/.../Picture1.jpg");
byte[] bytes = new byte[3000];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStream out = socket.getOutputStream();
int count;
out.write(("incoming_file"+"\0").getBytes(Charset.forName("UTF-8")));
String st;
int i = 0;
while((st = input.readLine()) != null)
{
switch (st)
{
case "send data":
System.out.println("data: "+st);
System.out.println("File name: "+file.getName().trim());
out.write((file.getName()+"\0").getBytes("UTF-8"));
out.flush();
break;
case "file created":
System.out.println("data: "+st);
while ((count = bis.read(bytes)) > 0)
{
System.out.println(count);
out.write(bytes, 0, count);
}
out.flush();
fis.close();
bis.close();
System.out.println("file sending complete"); //this gets printed
break;
case "file uploaded": //never comes here
System.out.println("data: "+st);
break;
default:
System.out.println("in default: "+st);
break;
}
System.out.println(i++);
}
out.flush();
out.close();
input.close();
}
catch(IOException ioe)
{
System.out.println("Exception during communication. Server closed connection.");
ioe.printStackTrace();
}
finally
{
try
{
// Close the socket before quitting
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
答案 0 :(得分:0)
this line from the man page for recv() contains the answer:
" If no messages are available at the socket, the receive calls wait for
a message to arrive,"
a MUCH better method is to code a select() (with timeout)/recv() loop.
Then when a timeout occurs, the file transfer is completed.
remember to refresh time timeout value each time through the loop.
use a reasonable timeout, say 1 second, to allow for
network and similar delays.
I.E.
while(forever)
// refresh timeout value
// result = select(...)
// note: result value: 0 == timeout, <0 == error, >0 == data received
// if 0 < result
// then, recv()
// else exit loop
end while
// if 0==result
// then all ok
// else if 0 > result
// then handle error
// endif
答案 1 :(得分:0)
您需要更复杂的协议。通常,不能被动地确定远程机器何时关闭连接或停止传输数据。
接近传输结束问题的一种方法是客户端在文件本身之前发送文件大小 - 然后当服务器收到许多字节时,它知道它有整个文件。另一种方法是将文件包装成具有可识别边界的格式,例如MIME或SOAP信封。
即便如此,客户端可能会在传输过程中出现故障或断开连接,因此对于健壮的服务器,您需要使用select()
超时以防止尝试执行注定要阻止的读取永远。