基本上我会在一段时间内使用recv来读取客户端发送的数据。客户端完成读取文件并发送它,但服务器仍然存在。如何通知服务器文件发送完成意味着客户端的feof?
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h> /*For Sockets*/
#include <sys/socket.h> /*For Sockets*/
#include <netdb.h> /*For gethostbyaddr()*/
#include <netinet/in.h> /*For internet sockets*/
#include <dirent.h>
/*Function for creating the lof file of Server*/
void log_event (char *message,char *filename)
{
FILE *file;
char *log_this;
time_t system_time; //Get the system time
time(&system_time);
log_this=strcat(ctime(&system_time),message); //Create the message to log
/*Check for filename and log as appropiate*/
if (filename!=NULL)
{
file = fopen(filename,"a+");
fprintf(file,"%s",log_this); /*writes the message*/
fclose(file); /*done!*/
}
else
{
file = fopen("ftp_tracelog.txt","a+");
fprintf(file,"%s",log_this); /*writes the message*/
fclose(file); /*done!*/
}
}
int main (int argc,char *argv[])
{
/*DECLERATIONS*/
char *filename;
char message [1024];
char *temp;
char temp_2[1024];
char buf[1024];
char *p=buf;
ssize_t bytesRemaining = 1024;
ssize_t bytesRemaining2 = 50;
char request[50];
char command[5];
char c[50];
char copy[1024]="COPY_OF_";
FILE *fp;
DIR *dp;
char list[1024];
int port,sock,newsock,serverlen,clientlen,fname_len,recvMsgSize,i,len,count;
struct sockaddr_in server,client;
struct sockaddr *serverptr, *clientptr;
struct hostent *rem;
struct dirent *ep;
/*END OF DECLERATIONS*/
/*Check for required arguments and get them as appropiate*/
if (argc < 2) {
/* Check if server's port number is given */
printf("Please give the port number!!!\n");
exit(1);
}
/*if server's port number is given and filename for log is given*/
if(argc>2){
filename=argv[1];
port=atoi(argv[2]);
}
/*If only port is given*/
if (argc==2){
port=atoi(argv[1]);
filename=NULL;
}
temp="--Server is Starting!!--";
sprintf(message,"%s\n",temp);
log_event(message,filename);
/* Create socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{perror("socket"); exit(1); }
server.sin_family = PF_INET; /* Internet domain */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* My Internet address */
server.sin_port = htons(port); /* The given port */
serverptr = (struct sockaddr *) &server;
serverlen = sizeof (server);
/* Bind socket to address */
if (bind(sock, serverptr, serverlen) < 0) {
perror("bind"); exit(1); }
/* Listen for connections */
if (listen(sock, 40) < 0) { /* 5 max. requests in queue */
perror("listen"); exit(1); }
temp="---Listening for connections to port";
sprintf(temp_2,"%d----",port);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/*Accepting Connecttion*/
while(1) {
clientptr = (struct sockaddr *) &client;
clientlen = sizeof(client);
/* Accept connection */
if ((newsock = accept(sock, clientptr, &clientlen)) < 0){
perror("accept"); exit(1);}
/* Find client's address */
if ((rem = gethostbyaddr((char *) &client.sin_addr.s_addr,
sizeof (client.sin_addr.s_addr), client.sin_family)) == NULL) {
perror("gethostbyaddr"); exit(1);}
temp="----Accepted connection from ";
sprintf(temp_2,"%s----", rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/* Create child for serving the client */
switch (fork()) {
case -1:
perror("fork"); exit(1);
case 0: /* Child process */
do{
/* Receive message from client */
if ((recvMsgSize = recv(newsock,request,sizeof(request),0))< 0)
perror("recv() failed");
printf("%s\n",request);
//printf("%s\n",command);
/*IF YOU ARE GOING TO EXECUTE AN LS COMMAND*/
if (strcmp(request,"ls")==0)
{
dp = opendir ("./");
if (dp != NULL)
{ /*LOG LS REQUEST*/
temp="--Client ";
sprintf(temp_2,"%s requested ls -------",rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/*SEND ALL DIRECTORY LISTING*/
while (ep = readdir (dp))
{
strcpy(list,ep->d_name);
//printf("sending:%s\n",list);
if (send(newsock,list,sizeof(list), 0)!= sizeof(list))
perror("send() sent a different number of bytes than expected");
}
//IF DIRECORY IS FINISHED SEND A LAST MESSAGE FOR ENDING
(void) closedir (dp);
if (send(newsock,"end",sizeof("end"), 0)!= sizeof("end"))
perror("send() sent a different number of bytes than expected");
}
else
perror ("Couldn't open the directory");
}
/*IF THE COMMAND IS PUT*/
if (strcmp(request,"put")==0)
{
sprintf(buf,"");
printf("execute put!!\n");
do{
ssize_t recvd;
while (bytesRemaining) {
if (( recvd =recv(newsock,p,bytesRemaining,0))< 0){
perror("recv() failed");}
bytesRemaining -= recvd; // keep track of bytes left
p += recvd;
}
}while (buf=="");
strcat(copy,buf);
fp=fopen(copy,"w+");
count=0;
while (c!="")
{
bzero(c,sizeof(c));
if ((recvMsgSize = recv(newsock,c,sizeof(c),0))< 0)
perror("recv() failed");
fprintf(fp,"%s",c);
}
fclose(fp);
printf("!!DONE!!!!\n");
//printf("%s",request);
}
}while (strcmp(request,"end")!=0); //run until client sents end request
/*LOG EXIT OF CLIENT*/
temp="--Client";
sprintf(temp_2,"%s is disconnected---",rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
close(newsock); /* Close socket */
exit(0);
} /* end of switch */
}/*end of while*/
}
客户端
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
int main (int argc,char *argv[])
{
int port, sock, serverlen,recvMsgSize,was_read;
int fname_len,msg_len,request_len;
char buf[256];
char *fname;
char request[50];
char list[1024];
char msg[512];
char op[1000];
char temp[5];
char *temp3;
char read;
FILE *fp;
char b[50];
struct sockaddr_in server;
struct sockaddr *serverptr;
struct hostent *rem;
temp3="put";
/* Are server's host name and port number given? */
if (argc < 3) {
printf("Please give host name and port number\n"); exit(1);
}
/* Create socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
/* Find server address */
if ((rem = gethostbyname(argv[1])) == NULL) {
herror("gethostbyname"); exit(1);
}
/* Convert port number to integer */
port = atoi(argv[2]);
/* Internet domain */
server.sin_family = PF_INET;
bcopy((char *) rem -> h_addr, (char *) &server.sin_addr,
rem -> h_length);
/*Server's Internet address and port*/
server.sin_port = htons(port);
serverptr = (struct sockaddr *) &server;
serverlen = sizeof(server);
if (connect(sock, serverptr, serverlen) < 0) { /* Request connection */
perror("connect");
exit(1); }
printf("Requested connection to host %s port %d\n", argv[1], port);
do{
printf("Please enter request\n:");
scanf("%s",request);
/* Send the string to the server */
if (send(sock,request,sizeof(request), 0)!= sizeof(request))
perror("send() sent a different number of bytes than expected");
if(strcmp(request,"ls")==0)
{
sprintf(list,"");
/*Recieve from server*/
while(strcmp(list,"end")!=0){
if ((recvMsgSize = recv(sock,list,sizeof(list),0))< 0)
perror("recv() failed");
if(strcmp(list,"end")!=0){
printf("%s\n",list);
}
}
bzero(request,sizeof(request));
}
/*Command for put*/
if(strcmp(request,"put")==0)
{ bzero(request,sizeof(request));
bzero(list,sizeof(list));
printf("Please enter filename:\n");
scanf("%s",list);
//printf("%s",list);
if (send(sock,list,sizeof(list), 0)!= sizeof(list))
perror("send() sent a different number of bytes than expected");
fp=fopen(list,"r");
if(fp==NULL)
{
puts ( "Cannot open target file" ) ;
fclose (fp) ;
exit(0);
}
while(!feof(fp))
{
bzero(b,sizeof(b));
int was_read = fread(b, sizeof(char),50,fp);
if (send(sock,b,(sizeof (char) * was_read), 0)!= (sizeof (char) * was_read))
perror("send() sent a different number of bytes than expected");
}
zero(b,sizeof(b));
if (send(sock,b,sizeof(b), 0)!= sizeof(b))
perror("send() sent a different number of bytes than expected");
}
}while (strcmp(request,"end")!=0);
close(sock); /* Close socket */
exit(0);
}
答案 0 :(得分:1)
一种方法是让客户端关闭文件末尾的套接字。服务器将成功从recv()
接收0个字节,这意味着另一端干净地关闭了套接字。我注意到您当前没有在服务器代码中检测到此返回值,但您应该这样做。
我注意到您的协议可以请求多个文件。在这种情况下,您需要执行诸如在发送实际文件之前发送文件中的字节数之类的操作,然后服务器将知道预期的字节数。或者,你可以像FTP那样做,并为文件数据打开第二个套接字连接(一次一个文件)。
作为一种风格说明,代码中的缩进很糟糕。很难读出来找出块的开始和结束位置。我会在代码审查中拒绝这段代码,纯粹是基于格式化的原因。