我在 Linux 环境中编写多线程 ftp 协议时遇到分段错误问题。这种分割是由于 fclose() 文件功能。
这是我的代码
客户端代码:它测试客户端作为命令编写的任何内容。例如,如果他写“put filename”,它会通过打开这个文件将这个文件发送到服务器,将它逐个流读取到缓冲区中。这些流通过套接字发送到服务器端。
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h> /* struct sockaddr_in, htons() */
#include <arpa/inet.h> /* inet_aton() */
#include <stdlib.h>
#define BUF_LENGTH 100
/*void getcmdstring(char ** args, char *cmd)
{
int i=0;
char * pch;
pch = strtok (cmd," ");
while (pch != NULL)
{
//args[i]=pch;
stpcpy(args[i],pch);
printf("%s,",args[i]);
//printf("%s,",pch);
pch = strtok (NULL, " ");
i++;
}
//args[i]=NULL;
//return argsVar;
}*/
int main(int argc, char ** argv)
{
int port;
int sock = -1;
struct sockaddr_in address;
//struct hostent * host;
int len;
//char ** args;
/* checking commandline parameter */
if (argc != 3)
{
printf("usage: %s hostIP port \n", argv[0]);
return -1;
}
/* obtain port number */
if (sscanf(argv[2], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
// port = atoi(argv[2]);
/* create socket */
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <= 0)
{
fprintf(stderr, "%s: error: cannot create socket\n", argv[0]);
return -3;
}
/* connect to server */
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
if(inet_aton(argv[1], &address.sin_addr) <=0){
fprintf(stderr,"inet_aton error for %s\n", argv[1]);
return -4;
}
/*host = gethostbyname(argv[1]);
if (!host)
{
fprintf(stderr, "%s: error: unknown host %s\n", argv[0], argv[1]);
return -4;
}
memcpy(&address.sin_addr, host->h_addr_list[0], host->h_length);*/
if (connect(sock, (struct sockaddr *)&address, sizeof(address))<0)
{
fprintf(stderr, "%s: error: cannot connect to host %s\n", argv[0], argv[1]);
return -5;
}
char cmd[4096], cmd2[4096];
char *fileS_path;
char cwd[2048];
char buf_S[BUF_LENGTH];
int varS;
char *fileR_path;
char cwd2[2048];
char buf_R[BUF_LENGTH];
int varR, varR2;
char ** res = NULL;
char * p = strtok (cmd2, " ");
int n_spaces = 0, i;
FILE *fileS;
while(1){
printf("ftp>");
fgets(cmd,4096,stdin);
strcpy(cmd2, cmd);
//printf("Cmd just after fgets: %s\n", cmd);
p = strtok (cmd2, " ");
n_spaces = 0;
if(cmd==NULL || strcmp(cmd, "")==0)
printf("Something wrong with reading the command from the screen\n");
else
{
/* split string and append tokens to 'res' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
p = strtok (NULL, " \n");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("res[%d] = %s\n", i, res[i]);
//printf("bar");
//printf("%s test before sending to socket\n", cmd);
//if(write(sock, cmd, 4096)<0)
//printf("problem with sending the socket command \n");
//else
//{
if(strcmp(res[0], "quit\n")==0)
break;
else if(res[0]!=NULL && res[1] !=NULL && strcmp(res[0], "put")==0)
{
if(write(sock, cmd, 4096)<0)
printf("problem with sending the socket command \n");
else{
// Sending file from the client to the server
printf("\n");
printf("****SENDING****\n");
if(getcwd(cwd,sizeof(cwd))!=NULL)
{
fileS_path=cwd;
strcat(fileS_path, "/");
strcat(fileS_path, res[1]);
}
printf("Sending the file %s to the server...\n", fileS_path);
printf("%s\n", fileS_path);
fileS = fopen(fileS_path, "r");
printf("OK apres creation file\n");
if(fileS==NULL)
fprintf(stderr, "File %s is not found. \n", fileS_path);
else
{
printf("else after creation file\n");
bzero(buf_S,BUF_LENGTH);
printf("bzero buffer1\n");
varS=-1;
printf("after initializing varS %d \n", varS);
while((varS=fread(buf_S, sizeof(char), BUF_LENGTH,fileS))>0)
{
printf("entering to the file loop %d \n", varS);
if(write(sock, buf_S, varS)<0){
printf("erreur");
fprintf(stderr, "Cannot send the file %s \n", fileS_path); exit;}
bzero(buf_S,BUF_LENGTH);
printf("bzero buffer2\n");
}
printf("The file was sent from the client to the server\n");
if(fileS!=NULL)
fclose(fileS);
printf("close fileS");
}
}
}
else if(res[0]!=NULL && res[1] !=NULL && strcmp(res[0], "get")==0)
{
if(write(sock, cmd, 4096)<0)
printf("problem with sending the socket command \n");
else{
printf("\n\n");
// Receiving file from the server to the client
printf("****RECEIVING****\n");
if(getcwd(cwd2,sizeof(cwd2))!=NULL){
fileR_path = cwd2;
strcat(fileR_path, "/");
strcat(fileR_path, res[1]);
}
printf("Receiving the file %s from the SERVER...\n", fileR_path);
FILE *fileR = fopen(fileR_path, "w");
if(!fileR)
fprintf(stderr, "File %s cannot be opened. \n", fileR_path);
else
{
bzero(buf_R,BUF_LENGTH);
varR =-1; varR2 =-1;
while((varR=read(sock, buf_R, BUF_LENGTH))>=0)
{
varR2=fwrite(buf_R, sizeof(char), varR,fileR);
if (varR2< varR)
fprintf(stderr, "Cannot write the file %s on the client \n", fileR_path);
bzero(buf_R,BUF_LENGTH);
if(varR == 0 || varR !=BUF_LENGTH)
break;
}
if(varR<0){
printf("Receiving failure while reading from the socket\n"); return -8;}
printf("The file was received from the SERVER to the CLIENT\n\n");
fclose(fileR);
}
}
}
else if( res[0]!=NULL && strcmp(res[0], "cd\n")==0)
{
if(write(sock, cmd, 4096)<0)
printf("Problem with sending the socket command \n");
if(read(sock, cwd, sizeof(cwd))<0)
printf("Problem reading the current working directory of the server \n");
else
printf("CWD of the server: %s",cwd);
}
else
{
printf("Wrong command, please try again\n");
}
//}
bzero(cmd, 4096);
printf("bzero cmd\n");
/* free the memory allocated */
free (res);
printf("free res\n");
}
}
/* close socket */
close(sock);
printf("exit now\n");
return 0;
}
服务器端:尝试通过套接字捕获命令。然后,它测试该命令是否为有效命令。例如,如果它是一个 put 命令,它会通过套接字读取来自客户端的流(读取)。然后,打开一个文件并将这些流写入其中。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <unistd.h>
//#include <netinet/in.h> /* struct sockaddr_in, htons() */
//#include <arpa/inet.h> /* inet_aton() */
#include <string.h>
#define BUF_LENGTH 100
#define MAXQ 10
typedef struct
{
int sock;
struct sockaddr address;
int addr_len;
} connection_t;
void * process(void * ptr)
{
char * buffer;
int len;
connection_t * conn;
long addr = 0;
char cmd[4096], cmd2[4096];
char ** res = NULL;
char * p = strtok (cmd2, " ");
int n_spaces = 0, i;
char *fileR_path;
char cwd[2048];
char buf_R[BUF_LENGTH];
FILE * fileR;
int varR, varR2;
if (!ptr) pthread_exit(0);
conn = (connection_t *)ptr;
while (1) // (strcmp(res[0],"exit")!=0)
{
printf("before reading the socket\n");
if(read(conn->sock, cmd, 4096)<0)
printf("Problem with reading the command from the server\n");
if (cmd ==NULL || strcmp(cmd, "")==0)
printf("receiving NULL command\n");
else
{
printf("After getting the command %s\n", cmd);
strcpy(cmd2, cmd);
p = strtok (cmd2, " ");
n_spaces = 0;
/* split string and append tokens to 'res' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
p = strtok (NULL, " \n");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("res[%d] = %s\n", i, res[i]);
printf("bar");
printf("%s test before sending to socket\n", cmd);
if((res[0] != NULL) && (res[1] != NULL) && strcmp(res[0],"put")==0)
{
/* Receiving File from the client in the server directory */
printf("\n****RECEIVING****\n");
if(getcwd(cwd,sizeof(cwd))!=NULL){
fileR_path = cwd;
strcat(fileR_path, "/");
strcat(fileR_path, res[1]);}
printf("Receiving the file %s from the client...\n", fileR_path);
fileR = fopen(fileR_path, "w");
if(fileR==NULL)
fprintf(stderr, "File %s cannot be opened. \n", fileR_path);
else
{
bzero(buf_R, BUF_LENGTH);
varR =-1 ; varR2=-1;
while((varR=read(conn->sock, buf_R, BUF_LENGTH))>=0)
{
varR2=fwrite(buf_R, sizeof(char), varR,fileR);
if (varR2< varR){
fprintf(stderr, "Cannot write the file %s on the server \n", fileR_path); exit;}
bzero(buf_R,BUF_LENGTH);
if((varR == 0 ) || (varR !=BUF_LENGTH)){
//printf("Something wrong with reading the socket \n");
break;
}
}
if(varR<0){
printf("Receiving failure due to error in reading socket\n");
//break;
exit;
}
printf("The file was received from the client to the server\n");
if(fileR!=NULL){
fclose(fileR);
printf("fileR closed\n");}
}
printf("\n");
}
else if ((res[0] != NULL) && (res[1] != NULL) && strcmp(res[0], "get")==0)
{
// Sending file from the server to the client
printf("\n****SENDING****\n");
char *fileS_path;
char cwd2[2048];
if(getcwd(cwd2,sizeof(cwd2))!=NULL){
fileS_path=cwd2;
strcat(fileS_path, "/");
strcat(fileS_path, res[1]);
}
char buf_S[BUF_LENGTH];
printf("Sending the file %s to the CLIENT...\n", fileS_path);
FILE *fileS = fopen(fileS_path, "r");
if(!fileS)
fprintf(stderr, "File %s is not found. \n", fileS_path);
else
{
bzero(buf_S,BUF_LENGTH);
int varS;
while((varS=fread(buf_S, sizeof(char), BUF_LENGTH,fileS))>0)
{
if(write(conn->sock, buf_S, varS)<0){
fprintf(stderr, "Cannot send the file %s \n", fileS_path); break;}
bzero(buf_S,BUF_LENGTH);
}
printf("The file was sent from the SERVER to the CLIENT\n\n");
fclose(fileS);
}
}
else if (res[0]!=NULL && strcmp(res[0], "cd\n")==0)
{
if(getcwd(cwd,sizeof(cwd))!=NULL){
if(write(conn->sock, cwd, sizeof(cwd))<0){
printf("Cannot send the current working directory \n");
}
}
}
else if (strcmp(res[0], "quit")==0)
exit; //break;
bzero(cmd, 4096);
printf("bzerocmd\n %s", cmd);
free(res);
printf("free res\n");
}
}
/* close socket and clean up */
close(conn->sock);
printf("socket closed\n");
free(conn);
printf("Connection free\n");
pthread_exit(0);
printf("Thread exit\n");
}
int main(int argc, char ** argv)
{
int sock = -1;
struct sockaddr_in address;
int port;
connection_t * connection;
pthread_t thread;
/* check for command line arguments */
if (argc != 2)
{
fprintf(stderr, "usage: %s port\n", argv[0]);
return -1;
}
/* obtain port number */
if (sscanf(argv[1], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
/* create socket */
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <= 0)
{
fprintf(stderr, "%s: error: cannot create socket\n", argv[0]);
return -3;
}
/* bind socket to port */
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
{
fprintf(stderr, "%s: error: cannot bind socket to port %d\n", argv[0], port);
return -4;
}
/* listen on port */
if (listen(sock, MAXQ) < 0)
{
fprintf(stderr, "%s: error: cannot listen on port\n", argv[0]);
return -5;
}
printf("%s: ready and listening\n", argv[0]);
while (1)
{
/* accept incoming connections */
connection = (connection_t *)malloc(sizeof(connection_t));
connection->sock = accept(sock, &connection->address, &connection->addr_len);
if (connection->sock <= 0)
{
free(connection);
}
else
{
/* start a new thread but do not wait for it */
pthread_create(&thread, 0, process, (void *)connection);
pthread_detach(thread);
}
}
return 0;
}
这里的问题,以 put 命令为例(然而,它对于 get 命令是一样的),在第一次迭代中一切都很好。文件被复制,程序看起来很好。但是,在第二次迭代中(我的意思是当我在客户端第二次输入命令时)文件被复制到服务器端,并且在双方(服务器和客户端)都显示分段错误。我试图了解这个分段错误是从哪里来的,所以发现程序在 fclose 函数处停止。我不明白为什么?有什么帮助吗?