首先献上我的代码:
server.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MYPORT 5588
#define FILE_BLOCK 1048576
#define MAX_FILENAME_LEN 5000
void run();
void push_file(int fd,char* cmd);
void pull_file(int fd,char* cmd);
int main(int argc,char **argv){
switch(fork()){
case -1:
puts(“cannot fork\n”);
exit(-1);
case 0:
setsid();
switch(fork()){
case -1:
puts(“cannot fork\n”);
exit(-1);
case 0:
// close(0);
// close(1);
// close(2);
chdir(“/”);
run();
break;
default:
exit(0);
}
default:
exit(0);
}
run();
return 0;
}
void run(){
int socket_fd,connect_fd,remote_addr_len,msg_len;
struct sockaddr_in local_addr,remote_addr;
char recv_cmd =(char) malloc(MAX_FILENAME_LEN);
if((socket_fd = socket(AF_INET,SOCK_STREAM,0))==-1){
perror(“socket\n”);
exit(-1);
}
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(MYPORT);
local_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(local_addr.sin_zero),8);
if((bind(socket_fd,&local_addr,sizeof(local_addr)))==-1){
perror(“bind\n”);
exit(-1);
}
if((listen(socket_fd,10))==-1){
perror(“listen\n”);
exit(-1);
}
while(1){
char *cmd = recv_cmd;
remote_addr_len = sizeof(remote_addr);
if((connect_fd=accept(socket_fd,&remote_addr,&remote_addr_len))==-1){
perror(“accept\n”);
exit(-1);
}
ssize_t real_len;
if((real_len=recv(connect_fd,cmd,MAX_FILENAME_LEN,0))==-1){
perror(“recv\n”);
exit(-1);
}
cmd[real_len] = ‘\0’;
puts(cmd);
if(!strncmp(cmd,“push”,4)){
cmd +=4;
push_file(connect_fd,cmd);
}
else if(!strncmp(cmd,“pull”,4)){
cmd+=4;
pull_file(connect_fd,cmd);
}
}
}
void push_file(int fd,char* filename){
FILE *lf;
ssize_t real_len;
void *tmpbuf = malloc(FILE_BLOCK);
if(!tmpbuf){
puts(“no enouch memory!\n”);
return;
}
real_len = recv(fd,tmpbuf,FILE_BLOCK,0);
if(real_len<0){
free(tmpbuf);
close(fd);
return;
}
lf = fopen(filename,“wb”);
if(!lf){
fprintf(stderr,“can not write file %s\n”,filename);
close(fd);
free(tmpbuf);
return;
}
fwrite(tmpbuf,1,real_len,lf);
while(1){
real_len = recv(fd,tmpbuf,FILE_BLOCK,0);
fwrite(tmpbuf,1,real_len,lf);
if(real_len<=0){
fclose(lf);
close(fd);
free(tmpbuf);
return;
}
}
}
void pull_file(int fd,char* filename){
int lf = open(filename,O_RDONLY);
if(fd==-1){
fprintf(stderr,“can not open file %s\n”,filename);
close(fd);
return;
}
struct stat file_stat;
fstat(lf,&file_stat);
off_t file_offset=0;
if(sendfile(fd,lf,&file_offset,file_stat.st_size)!=file_stat.st_size){
fprintf(stderr,“error occur when sending file %s\n”,filename);
}
close(fd);
close(lf);
}
client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILE_BLOCK 1048576
#define MAX_NAME_LEN 5000
void push_file(int fd,char*);
void pull_file(int fd,char*);
int main(int argc,char **argv){
int sock_fd;
struct sockaddr_in remote_addr;
char *local_file;
if(argc!=6){
fprintf(stderr,“use: %s ipaddr port push[|pull] localfile[|remotefile] remotefile[|localfile]\n”,argv[0]);
exit(-1);
}
if(strlen(argv[4])>MAX_NAME_LEN||strlen(argv[5])>MAX_NAME_LEN){
fprintf(stderr,“Error: filename too long!\n”);
exit(-1);
}
const char *remote_ip = argv[1];
const char *remote_port = argv[2];
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(atoi(remote_port));
remote_addr.sin_addr.s_addr = inet_addr(remote_ip);
bzero(&(remote_addr.sin_zero),8);
sock_fd = socket(AF_INET,SOCK_STREAM,0);
if(sock_fd==-1){
perror(“socket\n”);
exit(-1);
}
if((connect(sock_fd,&remote_addr,sizeof(remote_addr)))==-1){
perror(“connect\n”);
exit(-1);
}
if(!strcmp(argv[3],“push”)){
char cmd = (char) malloc(strlen(argv[3])+strlen(argv[5])+1);
strcpy(cmd,argv[3]);
strcat(cmd,argv[5]);
if((send(sock_fd,cmd,MAX_NAME_LEN,0))==-1){
perror(“send\n”);
}
free(cmd);
push_file(sock_fd,argv[4]);
}
else if(!strcmp(argv[3],“pull”)){
char cmd = (char) malloc(strlen(argv[3])+strlen(argv[4])+1);
strcpy(cmd,argv[3]);
strcat(cmd,argv[4]);
if((send(sock_fd,cmd,strlen(cmd),0))==-1){
perror(“send\n”);
}
free(cmd);
pull_file(sock_fd,argv[5]);
}
else{
fprintf(stderr,“no such command: %s\n”,argv[3]);
close(sock_fd);
}
}
void push_file(int fd,char *filename){
int lf = open(filename,O_RDONLY);
if(fd==-1){
fprintf(stderr,“can not open file %s\n”,filename);
close(fd);
return;
}
struct stat file_stat;
fstat(lf,&file_stat);
off_t file_offset=0;
if(sendfile(fd,lf,&file_offset,file_stat.st_size)!=file_stat.st_size){
fprintf(stderr,“error occur when transfering file %s \n”,filename);
}
close(fd);
close(lf);
}
void pull_file(int fd,char *filename){
void *tmpbuf = malloc(FILE_BLOCK);
if(!tmpbuf){
puts(“no enouch memory!\n”);
return;
}
ssize_t real_len = recv(fd,tmpbuf,FILE_BLOCK,0);
if(real_len<0){
fprintf(stderr,“file %s not found in remote pc.\n”,filename);
close(fd);
free(tmpbuf);
return;
}
FILE *lf = fopen(filename,“wb”);
if(!lf){
fprintf(stderr,“can not write file %s\n”,filename);
free(tmpbuf);
close(fd);
return;
}
fwrite(tmpbuf,1,real_len,lf);
while(1){
real_len = recv(fd,tmpbuf,FILE_BLOCK,0);
fwrite(tmpbuf,1,real_len,lf);
if(real_len<=0){
fclose(lf);
close(fd);
free(tmpbuf);
return;
}
}
}
软件意图很简单,就是传输文件,不过我不明白,send和recv这两个函数是不是成对出现的?有没有可能连续调用两次send后,只调用一次recv就把那两次send的数据全部接收完?或者一次send的数据需要两次recv才能接收完?
起初,我client端第一次send的时候,是send(sock_fd,cmd,strlen(cmd),0),结果server端第一次recv得到的数据中竟然包含有client端第二次发送的数据,表现为server端生成的文件名包含有文件魔数,比如发送png时名字最后有PNG,发送elf时名字含有ELF.