0

我使用 send 和 recv 在客户端和服务器之间传递消息。在服务器端,当我在缓冲区 fname 上收到一条消息时,保存的消息不是从客户端发送的整个消息

服务器

#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 fname[128];
char request[1024];
char op[1000];
char command[5];
FILE *fp;
DIR *dp;
char list[1024];
int port,sock,newsock,serverlen,clientlen,fname_len,recvMsgSize,i;
char buf[256];

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);

strncpy(command,request,4);
printf("%s\n",command);
/*IF YOU ARE GOING TO EXECUTE AN LS COMMAND*/

if (strcmp(command,"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(command,"put")==0) 
{
printf("execute put!!\n");

bzero(fname, sizeof fname); /* Initialize buffer */

if ((recvMsgSize = recv(newsock,fname,128, MSG_WAITALL)) < 0)
perror("recv() failed");

printf("%s!!!!\n",fname);

}
}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(1) */


}

客户

#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;
int fname_len,msg_len,request_len;
char buf[256];
char fname[128];
char request[1204];
char list[1024];
char msg[512];
char op[1000];
char temp[5];
char *temp3;
FILE *fp;


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);

request_len=sizeof(request);

/* Send the string to the server */
if (send(sock,request,request_len, 0)!= request_len)
perror("send() sent a different number of bytes than expected");

strncpy(temp,request,4);
printf("%s\n",temp);

if(strcmp(temp,"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);
        }
}
}

/*Command for put*/
if(strcmp(request,temp)==0)
{
printf("Please enter filename:\n");
scanf("%s",fname);

if (send(sock,fname,128, MSG_DONTWAIT)!= 128)
perror("send() sent a different number of bytes than expected");

}
}while (strcmp(request,"end")!=0);
close(sock); /* Close socket */
exit(0);
}
4

2 回答 2

4

当您调用 时recv,您需要检查接收到的字节数。如果它小于您的要求,您需要recv再次调用,并添加到先前接收到的缓冲区的末尾。可能发生的情况是,当您第一次调用时,只有部分消息到达recv

char buf[N];
char* p = buf;
ssize_t bytesRemaining = N;
while (bytesRemaining) {
   ssize_t recvd;
   recvd = recv(sock, p, bytesRemaining, 0);
   bytesRemaining -= recvd;     // keep track of bytes left
   p += recvd;                  // advance buffer pointer
}
于 2012-11-04T23:00:37.083 回答
1

永远不能依赖recv()函数在一个调用实例中接收所有数据。您可能必须在循环中重复调用它以获取所有数据(等于数据的长度。

于 2012-11-04T23:02:05.590 回答