我正在尝试编写用于文件传输的服务器 - 客户端应用程序。客户端是用Java编写的,服务器是用C ++编写的。
不幸的是我有以下错误:
java.net.SocketException:peer by peer:socket write error“
以下是我的客户代码:
import java.io.*;
import java.net.Socket;
public class Proba_binar
{
public static void main(String[] args)
{
byte[] buffer = null;
byte[] auxByte = new byte[1000];
String fileName = "1.jpg";
File a_file = new File(fileName);
try
{
// Create a socket
Socket socket = new Socket("192.168.14.146", 8888);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Read file
FileInputStream fis = new FileInputStream(fileName);
int length = (int)a_file.length();
buffer = new byte[length];
fis.read(buffer);
fis.close();
// Send file length
System.out.println("length = " + Integer.toString(length));
out.write(Integer.toString(length) + "\n");
out.flush();
// Send file
int imageSize = buffer.length;
char[] auxChar = new char[1000];
int nr_transf = imageSize / 1000;
int rest_byte = imageSize % 1000;
System.out.println("nr_transf = " + nr_transf);
for(int j = 0; j < nr_transf; j++)
{
// send series of 1000 bytes
for(int i = 0; i < 1000; i++)
{
auxChar[i] = (char)buffer[j*1000+i];
auxByte[i] = buffer[j*1000+i];
}
out.write(auxChar);
out.flush();
}
// send last bytes
for(int i = 0; i < rest_byte; i++)
{
auxChar[i] = (char)buffer[1000*nr_transf+i];
auxByte[i] = buffer[1000*nr_transf+i];
}
out.write(auxChar, 0, rest_byte);
out.flush();
out.close();
in.close();
socket.close();
System.out.println("Transfer finished!");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
服务器的代码:
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c, bytecount, nr_transf, rest_byte, i;
int recv_size, file_size;
char message[1000];
char buffer[1000];
int buffer_len = 1000;
FILE *f = fopen("out.jpg", "wb");
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
getch();
return 0;
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if(bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
getch();
return 0;
}
puts("Bind done");
//Listen to incoming connections
listen(s, 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(s, (struct sockaddr*)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d", WSAGetLastError());
getch();
return 0;
}
puts("Connection accepted");
//Receive FILE DIMENSION from client
if((recv_size = recv(new_socket, message, 1000, 0)) == SOCKET_ERROR)
{
puts("recv failed");
getch();
}
message[recv_size] = '\0';
file_size = atoi(message);
printf("\nfile_size = %d", file_size);
nr_transf = file_size / 1000;
rest_byte = file_size % 1000;
//Receive FILE from client
for(i = 0; i < nr_transf; i++)
{
// receive 1000 bytes
if((bytecount = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR)
{
printf("Receive failed auxChar");
getch();
return 0;
}
fwrite(buffer, 1, buffer_len, f);
}
// receive last bytes
if((bytecount = recv(new_socket, buffer, rest_byte, 0)) == SOCKET_ERROR)
{
printf("Receive failed rest_byte");
getch();
return 0;
}
fwrite(buffer, 1, rest_byte, f);
fclose(f);
printf("Receive finished!");
closesocket(s);
WSACleanup();
getch();
return 0;
}
我用Java制作了相同的服务器并且工作得很好。 我不知道c ++版本有什么问题。 提前谢谢!
答案 0 :(得分:0)
recv()
并不保证它会读取所有请求的字节:
...调用recv将返回当前可用的数据 - 达到指定缓冲区的大小...
这意味着for
/ recv
循环结构不正确,可能是服务器认为它已经读取了所有数据但却没有。这导致服务器在客户端发送所有数据之前关闭套接字,从而导致Java客户端报告错误。
recv
循环的示例(未经测试)重组:
int totalBytesRead = 0;
int bytesRead;
while (totalBytesRead < file_size)
{
if((bytesRead = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR)
{
/* Handle failure. */
break;
}
if (bytesRead != fwrite(buffer, 1, bytesRead, f))
{
/* Handle failure. */
break;
}
totalBytesRead += file_size;
}
请记住,连接的套接字是基于流的,使用mutilple send()
并不意味着匹配的recv()
将读取与发送时相同的“块”中的数据。除了已经提到的数据内容检索错误之外,这同样适用于读取文件大小。无法保证读取整个文件大小。
我建议设计一个简单的协议,以确保正确读取不同类型的数据。例如,客户端发送:
&LT; FILE_SIZE&GT; \ n&LT; FILE_CONTENT&GT;
服务器读取所有数据直到换行符并将其转换为文件大小。然后服务器确定它具有正确的文件大小。然后,服务器从套接字读取file_size
个字节。最后,服务器响应以指示成功或失败:
成功\ n
客户端读取换行符以获取响应。