我编写了一个应用程序,其中客户端使用使用tcp协议的套接字将文件发送到服务器。
我的服务器是多线程的(使用Pthread)。
只有一个问题,将文件复制到服务器较小(约2ko丢失)作为原始文件。为什么呢?
这是我的客户端代码,它开始输入./client filename filenamecopy
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
int fileSEND(char *server, int PORT, char *lfile, char *rfile){
int socketDESC;
struct sockaddr_in serverADDRESS;
struct hostent *hostINFO;
FILE * file_to_send;
int ch;
char toSEND[1];
char remoteFILE[4096];
int count1=1,count2=1, percent;
hostINFO = gethostbyname(server);
if (hostINFO == NULL) {
printf("L'adresse ip du serveur n'est pas accesible\n");
return 1;
}
socketDESC = socket(AF_INET, SOCK_STREAM, 0);
if (socketDESC < 0) {
printf("Erreur création socket\n");
return 1;
}
serverADDRESS.sin_family = hostINFO->h_addrtype;
memcpy((char *) &serverADDRESS.sin_addr.s_addr, hostINFO->h_addr_list[0], hostINFO->h_length);
serverADDRESS.sin_port = htons(PORT);
if (connect(socketDESC, (struct sockaddr *) &serverADDRESS, sizeof(serverADDRESS)) < 0) {
printf("Erreur de connection\n");
return 1;
}
file_to_send = fopen (lfile,"r");
if(!file_to_send) {
printf("Erreur de lecture du fichier\n");
close(socketDESC);
return 0;
} else {
long fileSIZE;
fseek (file_to_send, 0, SEEK_END); fileSIZE =ftell (file_to_send);
rewind(file_to_send);
sprintf(remoteFILE,"FBEGIN:%s:%i\r\n", rfile, fileSIZE);
send(socketDESC, remoteFILE, sizeof(remoteFILE), 0);
percent = fileSIZE / 100;
while((ch=getc(file_to_send))!=EOF){
toSEND[0] = ch;
send(socketDESC, toSEND, 1, 0);
if( count1 == count2 ) {
printf("33[0;0H");
printf( "\33[2J");
printf("Nom du fichier: %s\n", lfile);
printf("Taille du fichier: %i Kb\n", fileSIZE / 1024);
printf("Poucentage : %d%% ( %d Kb)\n",count1 / percent ,count1 / 1024);
count1+=percent;
}
count2++;
}
}
fclose(file_to_send);
close(socketDESC);
return 0;
}
int main(int argc, char* argv[])
{
fileSEND("127.0.0.1", 31338, argv[1], argv[2]);
return 0;
}
和服务器,由./server
启动#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#define PORT 31338
int parseARGS(char **args, char *line){
int tmp=0;
args[tmp] = strtok( line, ":" );
while ( (args[++tmp] = strtok(NULL, ":" ) ) != NULL );
return tmp - 1;
}
int client(void *ptr){
int connectSOCKET;
connectSOCKET = (int ) ptr;
char recvBUFF[4096];
char *filename, *filesize;
FILE * recvFILE;
int received = 0;
char tempstr[4096];
char *header[4096];
/*int i=0;
while(i<993199) {
i++;*/
while(1){
if( recv(connectSOCKET, recvBUFF, sizeof(recvBUFF), 0) ){
if(!strncmp(recvBUFF,"FBEGIN",6)) {
recvBUFF[strlen(recvBUFF) - 2] = 0;
parseARGS(header, recvBUFF);
filename = header[1];
filesize = header[2];
printf("Fichier: %s\n", filename);
printf("Taille: %d Kb\n", atoi(filesize) / 1024);
}
recvBUFF[0] = 0;
recvFILE = fopen ( filename,"w" );
while(1){
if( recv(connectSOCKET, recvBUFF, 1, 0) != 0 ) {
fwrite (recvBUFF , sizeof(recvBUFF[0]) , 1 , recvFILE );
received++;
recvBUFF[0] = 0;
} else {
printf("Progression: %s [ %d of %s bytes]\n", filename, received , filesize);
return 0;
}
}
return 0;
} else {
printf("Client déconnecté\n");
}
return 0;
}
}
int main()
{
int socketINDEX = 0;
int listenSOCKET, connectSOCKET[4096];
socklen_t clientADDRESSLENGTH[4096];
struct sockaddr_in clientADDRESS[4096], serverADDRESS;
pthread_t threads[4096];
listenSOCKET = socket(AF_INET, SOCK_STREAM, 0);
if (listenSOCKET < 0) {
printf("Peut pas crée socket\n");
close(listenSOCKET);
return 1;
}
serverADDRESS.sin_family = AF_INET;
serverADDRESS.sin_addr.s_addr = htonl(INADDR_ANY);
serverADDRESS.sin_port = htons(PORT);
if (bind(listenSOCKET, (struct sockaddr *) &serverADDRESS, sizeof(serverADDRESS)) < 0) {
printf("Peut pas trouver la socket\n");
close(listenSOCKET);
return 1;
}
listen(listenSOCKET, 5);
clientADDRESSLENGTH[socketINDEX] = sizeof(clientADDRESS[socketINDEX]);
int i=0;
/*while(i<993199) {
i++;*/
while(1){
connectSOCKET[socketINDEX] = accept(listenSOCKET, (struct sockaddr *) &clientADDRESS[socketINDEX], &clientADDRESSLENGTH[socketINDEX]);
if (connectSOCKET[socketINDEX] < 0) {
printf("Connection refusé\n");
close(listenSOCKET);
return 1;
}
pthread_create( &threads[socketINDEX], NULL, client, connectSOCKET[socketINDEX]);
if(socketINDEX=4096) {
socketINDEX = 0;
} else {
socketINDEX++;
}
}
close(listenSOCKET);
}
答案 0 :(得分:0)
两个问题:
您的客户端发送带有FBEGIN:filename:size标头的4K块。服务器尝试在一个4K块中读取它。 recv()
可以返回少于一个完整的缓冲区(最少1个字节)。
您的服务器在读取后不会关闭该文件。这可能导致文件大小不一致(当文件关闭时,缓冲的数据将被刷新)。
本身不是错误,但是性能问题:一次读取/写入/发送/接收一个字节 S-L-O-W 。你应该用更大的块来做任何事情(即使只有1K也会是一个巨大的性能提升)。请记住上面提到的“recv()
可能部分完成”问题。