题
我正在用 c 构建一个服务器客户端程序,并且在使用 send() 和 receive() 函数发送整个文件时遇到一些问题。我需要发送整个文件,但所有这些函数所能做的就是发送一个字符串。主要问题是发送 exe 或其他二进制格式数据。我应该使用 htons 还是 htonl func?我不知道如何使用这些,因为我只是一个菜鸟。
我被这个问题困扰并且喜欢你的帮助。谢谢!!
这是服务器端的recv函数::
if (socket_type != SOCK_DGRAM)
{
fi = fopen (final,"wb");
retval = recv(msgsock, recv_buf, strlen(recv_buf), 0);
/*recv_buf[retval] = '\0';
fprintf (fi,"%s",recv_buf);*/
int i;
i=atoi(recv_buf);
char *q;
q=(char *)malloc(i*sizeof(char));
retval = recv(msgsock, q, strlen(q), 0);
//printf ("%s",q);
fwrite(q,i,1,fi);
fclose(fi);
}
else
{
retval = recvfrom(msgsock,recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from, &fromlen);
printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
printf ("SOCK_DGRAM");
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
//continue;
}
else
printf("Server: recv() is OK.\n");
if (retval == 0)
{
printf("Server: Client closed connection.\n");
closesocket(msgsock);
//continue;
}
printf("Server: Received %d bytes, data from client\n", retval);
客户端发送函数:::
void send_command(){int bytesent;文件*file_out;//file_out = fopen(file_path,"rb");char str_all[100000];//标志[30]="end";
///////////////////////getsize//////////////
char fsize[5];
int filesize;
file_out = fopen(file_path, "rb");
fseek(file_out, 0, SEEK_END);
filesize = ftell(file_out);
rewind (file_out);
itoa (filesize,fsize,10);
/////////////////////////////////////////////
send (ConnectSocket, fsize, strlen (fsize), 0);
char *r = (char *)malloc (filesize * sizeof(char));
fread(r,filesize,1,file_out);
bytesent = send( ConnectSocket, r, strlen(r), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
fclose (file_out);
/*while (fscanf(file_out,"%s",&str_all) != EOF)
{
bytesent = send( ConnectSocket, str_all, strlen(str_all), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
//Sleep(500);
}*/
/*printf("%s",flag);
send( ConnectSocket, flag, strlen(flag), 0 );*/
WSACleanup();
//return 0;
}
解决方案
您需要自己实现该功能,或使用这样做的库。 send(2)
只是将原始字节的缓冲区。如果你想发送一个文件,你需要使用某种形式的的协议的,无论是客户端和服务器理解。
的最简单的可能的协议可能是在客户端发送的文件名,文件的长度,然后将原始文件数据。例如(检查为清楚起见省略错误):
// Server:
const char *filename = ...;
uint32_t filenameLen = strlen(filename);
uint32_t filenameLenNet = htonl(filenameLen);
send(fd, &filenameLenNet, sizeof(filenameLenNet), 0);
send(fd, filename, filenameLen, 0);
// You should probably use a 64-bit file length; also, for large files, you
// don't want to read the entire file into memory, you should just stream it
// from disk to network in reasonably-sized chunks.
const void *fileData = ...;
uint32_t fileLen = ...;
uint32_t fileLenNet = htonl(fileLen);
send(fd, &fileLenNet, sizeof(fileLenNet), 0);
send(fd, fileData, fileLen, 0);
// Client:
char *filename;
uint32_t filenameLen;
recv(fd, &filenameLen, sizeof(filenameLen), 0);
filenameLen = ntohl(filenameLen);
filename = malloc(filenameLen + 1);
recv(fd, filename, filenameLen, 0);
filename[filenameLen] = 0;
uint32_t fileLen;
recv(fd, &fileLen, sizeof(fileLen), 0);
fileLen = ntohl(fileLen);
void *fileData = malloc(fileLen);
recv(fd, fileData, fileLen, 0);
// Write file Data to the output file. Again, for large files, it would be
// better to stream it in in chunks instead of reading it all in at once.
此外,小心约局部发送/接收。确保你从send
和recv
检查返回值,因为他们可以(做)往往只能发送或接收你的意图发送或接收数据的一个子集。当发生这种情况,必须通过重新发送或在一个循环rereceiving直到已经处理所有你想要的数据或发生错误恢复。
其他提示
的send()不发送一个字符串,它发送的字节的阵列。你创建你的缓冲,填充,发送缓冲区,并通过它字节#发送(),并从那里。
根据您所使用的操作系统,可能会有 sendfile
命令;但不保证它可以在不同操作系统之间移植。最便携的方法就是 read()
将文件分块放入缓冲区,然后 write()
它出来了(或 send()
不过,如果你使用的是套接字的话 write()
应该也能正常工作)。
看 我对上一个问题的回答 本质上问的是同一件事。
您需要做的是在同一时间发送给您的数据在几个块,一个大块。所以,本质上你一次读取文件N个字节到缓冲区和send()的N个字节。