TCP 客户端不处理损坏的服务器在 C 中正确连接
TCP client not handling broken server connect correctly in C
我使用 TCP 创建了自己的 ftp server/client(一个非常简单的版本)。有 5 个可能的命令:ls-remote、ls-local、get、put 和 exit。此外,我在我的服务器代码中使用多处理,以便能够通过使用 fork() 同时处理多个客户端。除了我注意到的一件事外,一切都运行良好:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我会检查发送调用中的 return 值是否小于 0,然后关闭套接字,并调用 exit(-1) 来终止进程;但是,这会导致我的客户端挂起...
我的客户:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdio.h>
void readDirectory();
void syserr(char* msg)
{ perror(msg);
exit(-1);
}
int main(int argc, char* argv[])
{
int sockfd, portno, n;
struct hostent* server;
struct sockaddr_in serv_addr;
char buffer[256], temp[256];
if(argc < 3) {
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
return 1;
}
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if(!server) {
fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
return 2;
}
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't connect to server");
printf("Connection to %s:%s established. Now awaiting commands...\n\n\n", argv[1], argv[2]);
do{
printf("%s:%s> ", argv[1], argv[2]); //prompt user for command
fgets(buffer, 255, stdin);
n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n')
buffer[n-1] = '[=10=]';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
uint32_t size;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
size = ntohl(size);
int currentSize = 0;
printf("Files at the server: %s\n", argv[1]);
while(currentSize < size){
memset(&buffer[0], 0, sizeof(buffer));
n = recv(sockfd, buffer, 255, 0); // recieve directory from server
if(n < 0) syserr("can't recieve server");
currentSize = currentSize + n;
printf("%s", buffer);
}
}
else if(strcmp(buffer, "ls-local") == 0){ //display files from local directory
printf("Files at the client: \n");
readDirectory();
}
else if(strncmp(buffer, "get ", 4) == 0){ //downlaod file from server
if(strlen(buffer) < 5){ // no file was entered
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t fileSize;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &fileSize, sizeof(fileSize), 0); // get size of file
if(n < 0) syserr("can't receive from server");
fileSize = ntohl(fileSize);
if(fileSize == -1){
printf("%s\n", "File does not exist");
}
else{ // file exists
int totalBytes = 0;
int bytesWritten = 0;
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
memcpy(temp, fileName, strlen(fileName)); //copy filename into temp
temp[strlen(fileName)] = '[=10=]';
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
//receieve the bytes
n = recv(sockfd, buffer, sizeof(buffer), 0);
if(n < 0) syserr("can't receive from server");
//write the bytes
int b = fwrite(buffer, 1, n, fpNew);
if (b < 0)
syserr("error writing file");
if(n == 0){ // error reading on server side
break;
}
totalBytes = n + totalBytes;
bytesWritten = b + bytesWritten;
}
fclose(fpNew);
if(bytesWritten == fileSize) // all bytes read/written to file successfully
printf("Retrieval of file %s: successful.\n", temp);
else
printf("Retrieval of file %s: unsuccessful.\n", temp);
}
else{
syserr("couldnt open file for writing.");
}
}
}
}
else if(strncmp(buffer, "put ", 4) == 0){ // upload file to server
if(strlen(buffer) < 5){
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t commandSize = strlen(buffer);
uint32_t status;
memcpy(temp, buffer, strlen(buffer)); //copy buffer into temp
temp[strlen(buffer)] = '[=10=]';
// get name of file
char *fileName = strtok(temp, " ");
fileName = strtok(NULL, " ");
int bytes;
FILE *fp = fopen(fileName, "r"); // open the file
if(fp){ // file exists and opened
int totalBytes = 0;
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
// get file size
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(sockfd, &size, sizeof(size), 0);
if(n < 0) syserr("can't send to server");
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes...
bytes = fread(buffer, 1, sizeof(buffer), fp); // read bytes fromt he file
if(bytes < 0){
syserr("Error reading the file.");
}
totalBytes = totalBytes + bytes;
//send the bytes
n = send(sockfd, buffer, bytes, 0);
if(n < 0) syserr("can't send to server");
if(bytes == 0){ //error reading
break;
}
}
fclose(fp);
//recieve the final status
n = recv(sockfd, &status, sizeof(status), 0);
if(n < 0) syserr("can't receive from server");
status = ntohl(status);
if(totalBytes == fileSize && status == 1){ // successful on both ends
printf("Upload of file %s: successful.\n", fileName);
}
else{
printf("Upload of file %s: unsuccessful.\n", fileName);
}
}
else{
printf("%s\n", "File does not exist");
}
}
}else if(strcmp(buffer, "exit") == 0){
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
}
else{
if(strcmp(buffer, "exit") != 0)
printf("Error...invalid command.\nValid commands: ls-remote, ls-local, get <filename>, put <filename>, exit\n");
}
}while (strcmp(buffer, "exit") != 0);
printf("Connection to server %s:%s terminated, BYE now!\n", argv[1], argv[2]);
close(sockfd);
return 0;
}
void readDirectory(){
DIR *d = opendir(".");
struct dirent *dir;
if (d)
{
while((dir = readdir(d))!= NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
}
else{
syserr("Error...could not get files from directory.");
}
}
我的服务器:
#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 <dirent.h>
void syserr(char *msg){
perror(msg); exit(-1);
}
void errorHandling(char *msg, int newsockfd){
close(newsockfd);
perror(msg); exit(-1);
}
uint32_t directorySize();
void handle_client(int newsockfd);
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, clt_addr;
socklen_t addrlen;
if(argc < 1) {
fprintf(stderr,"Usage: %s <port>\n", argv[0]);
return 1;
}
if(argc == 1){
argv[1] = "5555";
}
portno = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't bind");
printf("bind socket to port %d...\n", portno);
listen(sockfd, 5);
for(;;){
printf("wait on port %d...\n", portno);
addrlen = sizeof(clt_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
if(newsockfd < 0) syserr("can't accept");
pid_t pid = fork();
if(pid < 0){
syserr("Error can't fork");
}
else if(pid == 0){ // child process
close(sockfd);
handle_client(newsockfd);
close(newsockfd);
break;
}
else{ // parent
close(newsockfd);
continue;
}
}
return 0;
}
uint32_t directorySize(int newsockfd){
DIR *d = opendir(".");
struct dirent *dir;
uint32_t count = 0;
if (d)
{
while((dir = readdir(d))!= NULL)
{
//count++;
count = strlen(dir->d_name) + count + 1;
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
return count;
}
void handle_client(int newsockfd){
// receieve command size from client
uint32_t commandSize;
int n;
char buffer[256];
while(1){
n = recv(newsockfd, &commandSize, sizeof(commandSize), 0); // receive size of command
if(n < 0) errorHandling("can't receive from client", newsockfd);
commandSize = ntohl(commandSize);
//recieve command
n = recv(newsockfd, buffer, commandSize, 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
else buffer[n] = '[=11=]';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
// get the size of the directory
uint32_t size = htonl(directorySize(newsockfd));
n = send(newsockfd, &size, sizeof(size), 0); // send size of directory
if(n < 0) errorHandling("can't send to client", newsockfd);
DIR *d = opendir(".");
struct dirent *dir;
if(d){
while((dir = readdir(d))!= NULL){
memset(&buffer[0], 0, sizeof(buffer));
strcpy(buffer, dir->d_name);
buffer[strlen(buffer)] = '\n';
// send file/folder names
n = send(newsockfd, buffer, strlen(buffer), 0);
if(n < 0)
errorHandling("can't receive from client", newsockfd);
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
}
else if (strncmp(buffer, "get", 3) == 0){ // if command is get
char *fileName = strtok(buffer, " "); // "get"
fileName = strtok(NULL, " "); // the name of the file
FILE *fp = fopen(fileName, "r");
if(fp){ // if file exists
int totalBytes = 0;
int bytes;
// get the size of the file
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(newsockfd, &size, sizeof(size), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes to read...
// read the bytes into the buffer
bytes = fread(buffer, 1, sizeof(buffer), fp);
if(bytes < 0){
errorHandling("Eorror reading bytes on server side", newsockfd);
}
//send the bytes
n = send(newsockfd, buffer, bytes, 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
if(bytes == 0) // error reading file; bytes should have been > 0
break;
totalBytes = totalBytes + bytes;
}
fclose(fp);
}
else{
// tell client file doesnt exist by sending -1
uint32_t dne = htonl(-1);
n = send(newsockfd, &dne, sizeof(dne), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
}
}
else if (strncmp(buffer, "put", 3) == 0){ // upload a file
int totalBytes = 0;
int bytesWritten = 0;
int b = 0;
uint32_t fileSize, status;
n = recv(newsockfd, &fileSize, sizeof(fileSize), 0);// receive the size of file
if(n < 0) errorHandling("can't receive from client", newsockfd);
fileSize = ntohl(fileSize);
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
n = recv(newsockfd, buffer, sizeof(buffer), 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
if(n == 0){ //bad file transfer on client side
break;
}
//write the bytes
b = fwrite(buffer, 1, n, fpNew);
if(b < n){ // error writing to file
break;
}
totalBytes = totalBytes + n; // bytes recived
bytesWritten = bytesWritten + b; //bytes written
}
fclose(fpNew);
if(bytesWritten != fileSize){ // not all bytes written
status = htonl(-1);
}
else{
status = htonl(1);
}
// send the status
n = send(newsockfd, &status, sizeof(status), 0);
if(n < 0) errorHandling("can't send client", newsockfd);
}
else{
errorHandling("could not open file for writing.", newsockfd);
}
}
else{ // command is exit
printf("%s\n", "closing connection");
close(newsockfd); // close the connection
break;
}
}
}
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
这还不够。如果 n == 0
对等方已关闭连接:您必须这样做并退出读取循环,或者在您的情况下实际上可能是整个过程。
我使用 TCP 创建了自己的 ftp server/client(一个非常简单的版本)。有 5 个可能的命令:ls-remote、ls-local、get、put 和 exit。此外,我在我的服务器代码中使用多处理,以便能够通过使用 fork() 同时处理多个客户端。除了我注意到的一件事外,一切都运行良好:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我会检查发送调用中的 return 值是否小于 0,然后关闭套接字,并调用 exit(-1) 来终止进程;但是,这会导致我的客户端挂起...
我的客户:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdio.h>
void readDirectory();
void syserr(char* msg)
{ perror(msg);
exit(-1);
}
int main(int argc, char* argv[])
{
int sockfd, portno, n;
struct hostent* server;
struct sockaddr_in serv_addr;
char buffer[256], temp[256];
if(argc < 3) {
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
return 1;
}
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if(!server) {
fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
return 2;
}
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't connect to server");
printf("Connection to %s:%s established. Now awaiting commands...\n\n\n", argv[1], argv[2]);
do{
printf("%s:%s> ", argv[1], argv[2]); //prompt user for command
fgets(buffer, 255, stdin);
n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n')
buffer[n-1] = '[=10=]';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
uint32_t size;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
size = ntohl(size);
int currentSize = 0;
printf("Files at the server: %s\n", argv[1]);
while(currentSize < size){
memset(&buffer[0], 0, sizeof(buffer));
n = recv(sockfd, buffer, 255, 0); // recieve directory from server
if(n < 0) syserr("can't recieve server");
currentSize = currentSize + n;
printf("%s", buffer);
}
}
else if(strcmp(buffer, "ls-local") == 0){ //display files from local directory
printf("Files at the client: \n");
readDirectory();
}
else if(strncmp(buffer, "get ", 4) == 0){ //downlaod file from server
if(strlen(buffer) < 5){ // no file was entered
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t fileSize;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &fileSize, sizeof(fileSize), 0); // get size of file
if(n < 0) syserr("can't receive from server");
fileSize = ntohl(fileSize);
if(fileSize == -1){
printf("%s\n", "File does not exist");
}
else{ // file exists
int totalBytes = 0;
int bytesWritten = 0;
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
memcpy(temp, fileName, strlen(fileName)); //copy filename into temp
temp[strlen(fileName)] = '[=10=]';
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
//receieve the bytes
n = recv(sockfd, buffer, sizeof(buffer), 0);
if(n < 0) syserr("can't receive from server");
//write the bytes
int b = fwrite(buffer, 1, n, fpNew);
if (b < 0)
syserr("error writing file");
if(n == 0){ // error reading on server side
break;
}
totalBytes = n + totalBytes;
bytesWritten = b + bytesWritten;
}
fclose(fpNew);
if(bytesWritten == fileSize) // all bytes read/written to file successfully
printf("Retrieval of file %s: successful.\n", temp);
else
printf("Retrieval of file %s: unsuccessful.\n", temp);
}
else{
syserr("couldnt open file for writing.");
}
}
}
}
else if(strncmp(buffer, "put ", 4) == 0){ // upload file to server
if(strlen(buffer) < 5){
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t commandSize = strlen(buffer);
uint32_t status;
memcpy(temp, buffer, strlen(buffer)); //copy buffer into temp
temp[strlen(buffer)] = '[=10=]';
// get name of file
char *fileName = strtok(temp, " ");
fileName = strtok(NULL, " ");
int bytes;
FILE *fp = fopen(fileName, "r"); // open the file
if(fp){ // file exists and opened
int totalBytes = 0;
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
// get file size
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(sockfd, &size, sizeof(size), 0);
if(n < 0) syserr("can't send to server");
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes...
bytes = fread(buffer, 1, sizeof(buffer), fp); // read bytes fromt he file
if(bytes < 0){
syserr("Error reading the file.");
}
totalBytes = totalBytes + bytes;
//send the bytes
n = send(sockfd, buffer, bytes, 0);
if(n < 0) syserr("can't send to server");
if(bytes == 0){ //error reading
break;
}
}
fclose(fp);
//recieve the final status
n = recv(sockfd, &status, sizeof(status), 0);
if(n < 0) syserr("can't receive from server");
status = ntohl(status);
if(totalBytes == fileSize && status == 1){ // successful on both ends
printf("Upload of file %s: successful.\n", fileName);
}
else{
printf("Upload of file %s: unsuccessful.\n", fileName);
}
}
else{
printf("%s\n", "File does not exist");
}
}
}else if(strcmp(buffer, "exit") == 0){
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
}
else{
if(strcmp(buffer, "exit") != 0)
printf("Error...invalid command.\nValid commands: ls-remote, ls-local, get <filename>, put <filename>, exit\n");
}
}while (strcmp(buffer, "exit") != 0);
printf("Connection to server %s:%s terminated, BYE now!\n", argv[1], argv[2]);
close(sockfd);
return 0;
}
void readDirectory(){
DIR *d = opendir(".");
struct dirent *dir;
if (d)
{
while((dir = readdir(d))!= NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
}
else{
syserr("Error...could not get files from directory.");
}
}
我的服务器:
#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 <dirent.h>
void syserr(char *msg){
perror(msg); exit(-1);
}
void errorHandling(char *msg, int newsockfd){
close(newsockfd);
perror(msg); exit(-1);
}
uint32_t directorySize();
void handle_client(int newsockfd);
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, clt_addr;
socklen_t addrlen;
if(argc < 1) {
fprintf(stderr,"Usage: %s <port>\n", argv[0]);
return 1;
}
if(argc == 1){
argv[1] = "5555";
}
portno = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't bind");
printf("bind socket to port %d...\n", portno);
listen(sockfd, 5);
for(;;){
printf("wait on port %d...\n", portno);
addrlen = sizeof(clt_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
if(newsockfd < 0) syserr("can't accept");
pid_t pid = fork();
if(pid < 0){
syserr("Error can't fork");
}
else if(pid == 0){ // child process
close(sockfd);
handle_client(newsockfd);
close(newsockfd);
break;
}
else{ // parent
close(newsockfd);
continue;
}
}
return 0;
}
uint32_t directorySize(int newsockfd){
DIR *d = opendir(".");
struct dirent *dir;
uint32_t count = 0;
if (d)
{
while((dir = readdir(d))!= NULL)
{
//count++;
count = strlen(dir->d_name) + count + 1;
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
return count;
}
void handle_client(int newsockfd){
// receieve command size from client
uint32_t commandSize;
int n;
char buffer[256];
while(1){
n = recv(newsockfd, &commandSize, sizeof(commandSize), 0); // receive size of command
if(n < 0) errorHandling("can't receive from client", newsockfd);
commandSize = ntohl(commandSize);
//recieve command
n = recv(newsockfd, buffer, commandSize, 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
else buffer[n] = '[=11=]';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
// get the size of the directory
uint32_t size = htonl(directorySize(newsockfd));
n = send(newsockfd, &size, sizeof(size), 0); // send size of directory
if(n < 0) errorHandling("can't send to client", newsockfd);
DIR *d = opendir(".");
struct dirent *dir;
if(d){
while((dir = readdir(d))!= NULL){
memset(&buffer[0], 0, sizeof(buffer));
strcpy(buffer, dir->d_name);
buffer[strlen(buffer)] = '\n';
// send file/folder names
n = send(newsockfd, buffer, strlen(buffer), 0);
if(n < 0)
errorHandling("can't receive from client", newsockfd);
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
}
else if (strncmp(buffer, "get", 3) == 0){ // if command is get
char *fileName = strtok(buffer, " "); // "get"
fileName = strtok(NULL, " "); // the name of the file
FILE *fp = fopen(fileName, "r");
if(fp){ // if file exists
int totalBytes = 0;
int bytes;
// get the size of the file
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(newsockfd, &size, sizeof(size), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes to read...
// read the bytes into the buffer
bytes = fread(buffer, 1, sizeof(buffer), fp);
if(bytes < 0){
errorHandling("Eorror reading bytes on server side", newsockfd);
}
//send the bytes
n = send(newsockfd, buffer, bytes, 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
if(bytes == 0) // error reading file; bytes should have been > 0
break;
totalBytes = totalBytes + bytes;
}
fclose(fp);
}
else{
// tell client file doesnt exist by sending -1
uint32_t dne = htonl(-1);
n = send(newsockfd, &dne, sizeof(dne), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
}
}
else if (strncmp(buffer, "put", 3) == 0){ // upload a file
int totalBytes = 0;
int bytesWritten = 0;
int b = 0;
uint32_t fileSize, status;
n = recv(newsockfd, &fileSize, sizeof(fileSize), 0);// receive the size of file
if(n < 0) errorHandling("can't receive from client", newsockfd);
fileSize = ntohl(fileSize);
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
n = recv(newsockfd, buffer, sizeof(buffer), 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
if(n == 0){ //bad file transfer on client side
break;
}
//write the bytes
b = fwrite(buffer, 1, n, fpNew);
if(b < n){ // error writing to file
break;
}
totalBytes = totalBytes + n; // bytes recived
bytesWritten = bytesWritten + b; //bytes written
}
fclose(fpNew);
if(bytesWritten != fileSize){ // not all bytes written
status = htonl(-1);
}
else{
status = htonl(1);
}
// send the status
n = send(newsockfd, &status, sizeof(status), 0);
if(n < 0) errorHandling("can't send client", newsockfd);
}
else{
errorHandling("could not open file for writing.", newsockfd);
}
}
else{ // command is exit
printf("%s\n", "closing connection");
close(newsockfd); // close the connection
break;
}
}
}
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
这还不够。如果 n == 0
对等方已关闭连接:您必须这样做并退出读取循环,或者在您的情况下实际上可能是整个过程。