Я пытаюсь реализовать клиент-серверную программу на C с TCP для упражнения. Сервер должен быть в состоянии обслуживать много клиентов. Клиенты запрашивают некоторые файлы, которые сервер отправляет им. Каждый раз, когда клиент заканчивается, сервер падает с ошибкой сегментации. Он печатает «конец службы», глядя на gdb, он также возвращает основной функции, но он никогда не печатает «prova» после вызова функции «service» внутри цикла.
Здесь вы можете увидеть мой сервер и ниже моего клиента
/*
* TEMPLATE
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <rpc/xdr.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 1024 /* Buffer length */
char *prog_name;
char *err="-ERR\r\n";
void service(int s);
uint32_t getFileCreationTime(char *filename);
int main (int argc, char *argv[])
{
int conn_request_skt; /* passive socket */
uint16_t lport_n, lport_h; /* port used by server (net/host ord.) */
int bklog = 2; /* listen backlog */
int s; /* connected socket */
socklen_t addrlen;
struct sockaddr_in saddr, caddr; /* server and client addresses */
prog_name = argv[0];
if (argc != 2)
{
printf("Usage: %s <port number>\n", prog_name);
exit(1);
}
/* get server port number */
if (sscanf(argv[1], "%" SCNu16, &lport_h)!=1)
err_sys("Invalid port number");
lport_n = htons(lport_h);
/* create the socket */
printf("creating socket...\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done, socket number %u\n",s);
/* bind the socket to any local IP address */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address", &saddr);
Bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
/* listen */
printf ("Listening at socket %d with backlog = %d \n",s,bklog);
Listen(s, bklog);
printf("done.\n");
conn_request_skt = s;
/* main server loop */
for (;;)
{
printf("loop again\n");
/* accept next connection */
addrlen = sizeof(struct sockaddr_in);
s = Accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s);
/* serve the client on socket s */
service(s);
printf("Prova\n");
}
return 0;
}
uint32_t getFileCreationTime(char *filename)
{
struct stat *attr;
stat(filename, attr);
return attr->st_mtime;
}
void service(int s)
{
char rbuf[BUFLEN+1]; /* reception buffer */
char buf[BUFLEN]; /* sending buffer */
char sbuf[BUFLEN]; /* buffer that will contain the dimension of the file */
int n;
char *get, *filename, filename_stats[20];
size_t len;
uint32_t bsent, dimension, modtime;
FILE *fp;
struct stat * fstatus;
for (;;)
{
n=recv(s, rbuf, BUFLEN-1, 0);
if (n < 0)
{
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
}
else if (n==0)
{
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
}
else
{
rbuf[n]=0;
get = strtok(rbuf, " ");
filename = strtok(NULL, "\r\n");
if(strcmp(get, "GET") == 0)
{
printf("\nA client requested the file '%s'\n", filename);
fp = fopen(filename, "rb");
if (fp == NULL)
{
printf("-ERR\tCould not open the file\n");
if(writen(s, err, 6) != 6)
printf("Write error\n");
}
fseek (fp, 0, SEEK_END);
dimension = ftell (fp);
//dimension--;
fseek (fp, 0, SEEK_SET);
sprintf(sbuf, "+OK\r\n");
printf("Sending:\n%s\n", sbuf);
if(writen(s, sbuf, 5) != 5)
printf("Write error\n");
//printf("Sending:\n%d\n", dimension);
//dimension = htonl(dimension);
//printf("dimension net=%d\n", dimension);
if(writen(s, &dimension, 4) != 4)
printf("Write error\n");
//dimension = ntohl(dimension);
printf("dimension=%d\n", dimension);
bsent=0;
while(bsent!=dimension)
{
if(dimension-bsent < BUFLEN)
{
//printf("bytes to send <BUFLEN\n");
fread (buf, 1, dimension-bsent, fp);
printf("Sending last %d bytes of the file\n", dimension-bsent);
if(writen(s, buf, dimension-bsent) != dimension-bsent)
printf("Write error\n");
bsent+=dimension-bsent;
}
else
{
//printf("bytes to send > BUFLEN\n");
fread (buf, 1, BUFLEN, fp);
//printf("Sending:\n%s\n", buf);
if(writen(s, buf, BUFLEN) != BUFLEN)
printf("Write error\n");
bsent+=BUFLEN;
printf("Bytes sent: %d\n", bsent);
}
}
fclose (fp);
modtime = getFileCreationTime(filename);
printf("Sending:\n%d\n", modtime);
//modtime = htonl(modtime);
if(writen(s, &modtime, 4) != 4)
printf("Write error\n");
printf("File '%s' correctly sent to the requesting client\n", filename);
}
else //invalid request
{
printf("-ERR\tINVALID REQUEST\n");
if(writen(s, err, 6) != 6)
printf("Write error\n");
}
}
}
printf("End of service\n");
return;
}
А вот и клиент:
/*
* TEMPLATE
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <rpc/xdr.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 1024 /* Buffer length */
char *prog_name;
int main (int argc, char *argv[])
{
char buf[BUFLEN]; /* transmission buffer */
char rbuf[BUFLEN]; /* receiving buffer */
char ok[5]; /* buffer used to receive the "+OK" message */
uint16_t tport_n, tport_h; /* server port number (net/host ord) */
char **filenames, *out="_out";
FILE* fp;
size_t len;
int s, result, i;
struct sockaddr_in saddr; /* server address structure */
struct in_addr sIPaddr; /* server IP addr. structure */
ssize_t nreadok, nread;
size_t nleft;
uint32_t breceived , bytes, timestamp;
prog_name = argv[0];
if(argc<4)
{
printf("Error! Usage: %s IP_addr port_number filename1 filename2 filename3 ...\n", prog_name);
return -1;
}
filenames = (char **) malloc(argc*sizeof(char*));
for(i=3; i<argc; i++)
{
filenames[i-3] = (char*) malloc (30*sizeof(char));
strcpy(filenames[i-3], argv[i]);
}
/* input IP address and port of server */
result = inet_aton(argv[1], &sIPaddr);
if (!result)
err_quit("Invalid address");
if (sscanf(argv[2], "%" SCNu16, &tport_h)!=1)
err_quit("Invalid port number");
tport_n = htons(tport_h);
/* create the socket */
printf("Creating socket\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done. Socket fd number: %d\n",s);
/* prepare address structure */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = tport_n;
saddr.sin_addr = sIPaddr;
/* connect */
showAddr("Connecting to target address", &saddr);
Connect(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
for(i=3; i<argc; i++)
{
//filename=argv[i];
sprintf(buf, "GET %s\r\n", filenames[i-3]); //creating the request "GET filename"
len = strlen(buf);
printf("\n%s", buf);
if(writen(s, buf, len) != len) //sending the request
{
printf("Write error\n");
}
printf("\nwaiting for response...\n");
//filename=argv[i];
//char rbuf[BUFLEN];
nread = readn(s, rbuf, 5); //receiving "+OK\r\n"
if(nread == 0)
printf("Connection closed\n");
if(rbuf[0] == '-')
{
nread = readn(s, rbuf, 1); //remaining byte of the "-ERR\r\n" message
if(nread==0)
printf("Connection closed\n");
printf("-ERROR! The server could not answer the request\n");
close(s);
return -1;
}
bytes=0;
//printf("Bytes 0=%d\n", bytes);
nread = readn(s, &bytes, 4); //receiving the dimension
if(nread == 0)
printf("Connection closed\n");
//printf("Bytes net=%d\n", bytes);
//bytes = ntohl(bytes);
printf("Dimension of the file = %d\n", bytes);
/*
nread = readn(s, rbuf, bytes-1); //receiving the file
if(nread == 0)
printf("Connection closed\n");
*/
strcat(filenames[i-3], "_copy");
fp = fopen(filenames[i-3], "wb"); //creating the file "filename_out"
if (fp == NULL)
{
printf("Could not open the file\n");
}
else
{
//coping data into the copy of the file
breceived=0;
while(1)
{
rbuf[0]=0;
if(bytes-breceived < BUFLEN)
{
//printf("bytes to receive <BUFLEN\n");
printf("Receiving: %d bytes of the file\n", bytes-breceived);
if(readn(s, rbuf, bytes-breceived) != bytes-breceived)
printf("Connection closed\n");
//printf("receiving:\n%s\n", rbuf);
//fputs(rbuf, fp);
fwrite(rbuf, 1, bytes-breceived, fp);
breceived+=bytes-breceived;
printf("Bytes received: %d\n", breceived);
break;
}
else
{
printf("bytes to receive(>BUFLEN) = %d\n", bytes-breceived);
//printf("receiving:\n%s\n", rbuf);
if(readn(s, rbuf, BUFLEN) != BUFLEN)
printf("Connection closed\n");
//printf("receiving:\n%s\n", rbuf);
//fputs(rbuf, fp);
fwrite(rbuf, 1, BUFLEN, fp);
breceived=breceived+BUFLEN;
printf("Bytes received: %d\n", breceived);
}
}
}
if(rbuf[0] == '-')
{
nread = readn(s, rbuf, 1); //remaining byte of the "-ERR\r\n" message
if(nread==0)
printf("Connection closed\n");
printf("-ERROR! The server could not answer the request\n");
close(s);
return -2;
}
//rbuf[bytes]=0;
nread = readn(s, ×tamp, 4); //receiving the timestamp
if(nread == 0)
printf("Connection closed\n");
//timestamp = ntohl(timestamp);
printf("\nFile received: '%s'\t %d bytes \t last mod: %d\n\n", filenames[i-3], bytes, timestamp);
fclose(fp);
}
printf("Closing the connection\n");
close(s);
return 0;
}