Я хотел написать простое приложение TCP echo server. Мне удалось выполнить часть эха, но у меня возникли проблемы с отправкой файлов между клиентом и сервером. Идея проста: несмотря на отправку обычных сообщений, клиент может отправить специальную команду на сервер (\ SENDFILE filename.txt), и после получения такой команды сервер должен запросить клиента для этого файла и получить файл с клиента. (Далее я хотел бы получить файл от одного клиента, а затем отправить его другому).
Я думаю, что "протокол" здесь прост, однако после ввода \SENDFILE на стороне клиента клиент зависает и не получает никаких дополнительных сообщений с сервера. Более того (сервер и клиент находятся в разных каталогах) на стороне сервера есть только пустой файл от клиента, без содержимого внутри.
Любые идеи, что здесь может быть неправильным?
client.c
#include<stdio.h> //printf
#include<string.h> //
#include <sys/stat.h>
#include<sys/socket.h> //socket
#include<arpa/inet.h> //inet_addr
#include <fcntl.h>
#define SERVER_PORT 9034
#define BUFF_SIZE 2000
int sendall(int s, char *buf, int len)
{
int total = 0;
int bytesleft = len;
int n;
while(total < len)
{
n = send(s, buf+total, bytesleft, 0);
if (n == -1)
break;
total += n;
bytesleft -= n;
}
return n==-1?-1:0;
}
void SendMsgToSender(char *msg, int connfd)
{
write(connfd, msg, strlen(msg));
memset(msg, 0, BUFF_SIZE);
}
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
char bufferOUT[BUFF_SIZE] , bufferIN[BUFF_SIZE];
struct stat file_stat;
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
// puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( SERVER_PORT );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("Connect failed. Error");
return 1;
}
// puts("Connected\n");
int read_size = 10;
//keep communicating with server
while(1)
{
printf("> ");
fgets(bufferOUT, BUFF_SIZE, stdin);
//Send some data
if( send(sock , bufferOUT , BUFF_SIZE , 0) < 0)
{
perror("Send failed");
return 1;
}
//Receive a reply from the server
if( (read_size = recv(sock , bufferIN , BUFF_SIZE , 0)) < 0)
{
perror("Recv failed");
break;
}
if(read_size == 0)
break;
if(bufferIN[0] == '\\')
{
char tmp[BUFF_SIZE], filename[BUFF_SIZE], *param;
memset(filename, BUFF_SIZE, 0);
strcpy(tmp, bufferIN);
param = strtok(tmp, " ");
if(param != NULL)
{
if(!strcmp(param, "\\GIVEMEFILE"))
{
param = strtok(NULL, " ");
if(param != NULL)
{
strcpy(filename, param);
FILE * fp;
int nBytes;
char buffer[BUFF_SIZE], *s;
memset(buffer, 0, BUFF_SIZE);
fp = fopen(filename, "r");
if(fp == NULL)
{
perror("fopen");
fflush(stdout);
break;
}
int remain_data = file_stat.st_size;
do
{
s = fgets(buffer, BUFF_SIZE, fp);
if(s != NULL && buffer[0] != EOF)
{
nBytes = sendall(sock, buffer, BUFF_SIZE);
remain_data -= nBytes;
}
else
break;
}
while((s != NULL) && (nBytes > 0) && (remain_data > 0));
fclose(fp);
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
continue;
}
}
}
}
else
{
printf("%s\n", bufferIN);
fflush(stdout);
}
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
}
close(sock);
return 0;
}
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#define SERVER_PORT 9034
#define BUFF_SIZE 2000
void StripNewline(char *s)
{
while(*s != '\0')
{
if(*s == '\r' || *s == '\n')
{
*s = '\0';
}
s++;
}
}
void SendMsgToSender(char *msg, int connfd)
{
write(connfd, msg, strlen(msg));
memset(msg, 0, BUFF_SIZE);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int GetFileFromClient(int connfd, char *filename)
{
FILE * fp = NULL;
int bytes;
char buffer[BUFF_SIZE];
memset(buffer, 0, BUFF_SIZE);
fp = fopen(filename, "w");
if(fp == NULL)
return 0;
memset(buffer, 0, BUFF_SIZE);
sprintf(buffer, "\\GIVEMEFILE %s \r\n", filename);
SendMsgToSender(buffer, connfd);
while(1)
{
memset(buffer ,0 , BUFF_SIZE);
if((bytes = recv(connfd , buffer , BUFF_SIZE , 0) ) <= 0)
return 0;
else
fprintf(fp, "%s\n", buffer);
}
fclose(fp);
sleep(1);
memset(buffer, 0, BUFF_SIZE);
sprintf(buffer, "\r\n");
SendMsgToSender(buffer, connfd);
return 1;
}
int main(void)
{
fd_set master;
fd_set read_fds;
int fdmax;
int listener;
int client_sock;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;
char bufferIN[BUFF_SIZE], bufferOUT[BUFF_SIZE], tmp[BUFF_SIZE], *datetime;
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1;
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
memset(tmp, 0, BUFF_SIZE);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
char port[16] = "9034";
if (getaddrinfo(NULL, port, &hints, &ai) < 0)
{
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0)
{
continue;
}
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0)
continue;
break;
}
if (p == NULL)
exit(2);
freeaddrinfo(ai);
if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
FD_SET(listener, &master);
fdmax = listener;
printf("Server is running ...\n\n");
for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{
addrlen = sizeof remoteaddr;
client_sock = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (client_sock == -1)
{
perror("accept");
}
else
{
FD_SET(client_sock, &master);
if (client_sock > fdmax)
fdmax = client_sock;
}
}
else
{
if ((nbytes = recv(i, bufferIN, BUFF_SIZE, 0)) <= 0)
{
if (nbytes == 0)
close(i);
else if(nbytes == -1)
{
perror("recv");
fflush(stdout);
}
close(i);
FD_CLR(i, &master);
}
else
{
bufferIN[nbytes-1] = '\0';
StripNewline(bufferIN);
strcpy(tmp, bufferIN);
if(bufferIN[0] == '\\')
{
char *command, *param;
command = strtok(bufferIN, " ");
if(!strcmp(command, "\\QUIT"))
{
close(i);
FD_CLR(i, &master);
break;
}
else if(!strcmp(command, "\\SENDFILE"))
{
param = strtok(tmp, " ");
if(param != NULL)
{
param = strtok(NULL, " ");
if(param != NULL)
{
printf("Client is sending me a file '%s'...\n", param);
GetFileFromClient(i, param);
}
}
}
else
{
SendMsgToSender(bufferIN, i);
}
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
}
else
{
SendMsgToSender(bufferIN, i);
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
return 0;
}