我试图使用TCP协议将文件从服务器传输到客户端。 我设法发送文件的整个syze,但是当客户端创建文件时,它无法打开。在这种情况下,即时发送jpg文件。
继承了server.c的代码:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 59000
int main(int argc,char *argv[]) {
int port, fd, newfd, n, nw, addrlen;
int port_was_given = 0;
char buffer[128], *ptr, *topic, *data;
size_t result;
struct hostent *h;
struct sockaddr_in addr;
FILE *send;
if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)exit(1); //error
memset((void*)&addr,(int)'\0',sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
if (argc == 3) {
port = atoi(argv[2]);
port_was_given = 1;
}
if(port_was_given == 1)
addr.sin_port=htons((u_short)port);
else
addr.sin_port=htons((u_short)PORT);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)exit(1); //error
if(listen(fd,5)==-1)exit(1); //error
while(1) {
addrlen=sizeof(addr);
if((newfd=accept(fd,(struct sockaddr*)&addr,&addrlen))==-1)exit(1); //erro
h=gethostbyaddr((char*)&addr.sin_addr,sizeof(struct in_addr),AF_INET);
while((n=read(newfd,buffer,128))!=0) {
if(n==-1)exit(1);
topic = strtok(buffer," ");
topic = strtok(NULL," ");
if (strcmp(topic, "Nacional\n")==0) {
send = fopen("flag","r");
fseek(send, 0L, SEEK_END); //vai ate ao fim do ficheiro
int sz = ftell(send); //size of file
fseek(send,0L,SEEK_SET);
//rewind(send);
data = (char*)malloc(sizeof(char)*sz);
result = fread(data,1,sz,send);
//fseek(send,0L,SEEK_SET);
fclose(send);
char ptr2[300] = "REP ok ";
char *ptrInt; //for s -> int
sprintf(ptrInt, "%d", sz);
strcat(ptr2, ptrInt);
strcat(ptr2, " ");
strcat(ptr2, data);
strcat(ptr2, "\n");
while(n>0) {
nw=write(newfd,ptr2,n); //write n bytes on each cycle
}
}
}
close(newfd);
}
close(fd);
exit(0);
}
好的逻辑是:客户端请求一种内容,在这种情况下内容是“Nacional”,因此服务器必须将“flag.jpg”发送给客户端。 服务器的答案有以下类型:
REP状态大小数据
状态可以是“ok”或“nok”。如果“nok”则不发送文件。 size是数据的大小。 data是文件本身的数据。
现在是client.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 58000
#define NG 10
int main (int argc,char *argv[])
{
/** ... variables delcarations and other stuff ... */
fdtcp=socket(AF_INET,SOCK_STREAM,0);
if (fdtcp==-1) exit(1); // Erro
inet_aton(ip, &address);
if (strcmp(lsname, "localhost")==0)
newHost = gethostbyname("localhost");
else
newHost = gethostbyaddr((const void *)&address,sizeof ip,AF_INET);
newPort = atoi(newport);
memset((void*)&addrtcp,(int)'\0',sizeof(addrtcp));
addrtcp.sin_family=AF_INET;
addrtcp.sin_addr.s_addr=((struct in_addr *)(newHost->h_addr_list[0]))->s_addr;
addrtcp.sin_port=htons((u_short)newPort);
k = connect(fdtcp,(struct sockaddr*)&addrtcp,sizeof(addrtcp));
if (k==-1) exit(1); // Erro
// REQ Tn (Conteudo Solicitado)
ptr = strcat(reqdata, tn);
ptr = strcat(reqdata, "\n");
// Envia-se o Comando REQ
nreqleft = 25;
while(nreqleft>0) {
kwrite=write(fdtcp,ptr,nreqleft);
if (kwrite<=0) exit(1); // Erro
nreqleft -= kwrite;
ptr += kwrite;
}
// Recebe-se o Comando REP
nreqleft = 128;
ptr = &buffertcp[0];
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
cmd = strtok(buffertcp, " "); // REP
cmd = strtok(NULL, " "); // Status
if(strcmp(cmd,"ok")) {
printf("ERR\n");
exit(1); // Erro
}
cmd = strtok(NULL, " "); // Size
size = atoi(cmd);
// Recebem-se os Dados do Conteúdo Desejado
nreqleft = size;
char data[size];
ptr = &data[0];
while(nreqleft>0) {
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
nreqleft -= kread;
ptr += kread;
}
file = fopen("file","w");
fwrite(data, 1, size, file);
fclose(file);
close(fdtcp);
// --------------------------------------------------- //
exit(0);
}
“其他东西”部分只是变量声明和与另一台服务器的UDP连接,这与这部分无关,所以我100%肯定它不会影响这部分。实际上,在client.c上,如果我放置从服务器收到的消息的printf,它将显示“REP ok 31800 ?????”哪个???我假设是文件的数据。
问题是创建的“文件”无法打开。帮助?
答案 0 :(得分:0)
一个问题是31800远大于300,因此当您将data
附加到服务器中的ptr2
数组时,就会出现缓冲区溢出。您可以在write()
中发送“标题”后,通过单独ptr2
来单独发送数据来更正此问题。你的write()
循环看起来会永远循环,但我猜你没有显示你的所有代码。
在接收器中,我没有看到任何尝试解析标头以将标头与数据分开的尝试。由于您最多读取128个字节,因此该读取可能已收到文件的标题和某些数据,并且您不会尝试检测并保存文件的该部分。
在调试文件传输应用程序时,我会从文本文件开始,以便您可以直观地看到生成的文件,并在您使用实际文件保存的文件上运行一个简单的diff
,以查看是否存在差异。