TCP客户端无法在C中正确处理断开的服务器连接
我使用TCP创建了自己的ftp服务器/客户端(一个非常简单的版本)。有5个可能的命令:ls remote、ls local、get、put和exit。此外,我在服务器代码中使用了多处理,以便能够通过使用fork()同时处理多个客户机。除了我注意到的一件事之外,一切都正常工作:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我检查发送调用的返回值是否小于0,然后关闭套接字,并调用exit(-1)终止进程;然而,这导致我的客户被绞死 我的客户:TCP客户端无法在C中正确处理断开的服务器连接,c,sockets,tcp,network-programming,client-server,C,Sockets,Tcp,Network Programming,Client Server,我使用TCP创建了自己的ftp服务器/客户端(一个非常简单的版本)。有5个可能的命令:ls remote、ls local、get、put和exit。此外,我在服务器代码中使用了多处理,以便能够通过使用fork()同时处理多个客户机。除了我注意到的一件事之外,一切都正常工作:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我检查发送调用的返回值是否小于0,然后关闭套接字,并调用exit(-1)终止进程;然而,这导致我的客户被绞死 我的客户: #include <
#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] = '\0';
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)] = '\0';
//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)] = '\0';
// 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.");
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
void readDirectory();
void syserr(字符*msg)
{perror(msg);
出口(-1);
}
int main(int argc,char*argv[])
{
int sockfd,端口号,n;
结构主机*服务器;
服务地址中的结构sockaddr\u;
字符缓冲区[256],临时缓冲区[256];
如果(argc<3){
fprintf(stderr,“用法:%s\n”,argv[0]);
返回1;
}
portno=atoi(argv[2]);
server=gethostbyname(argv[1]);
如果(!服务器){
fprintf(stderr,“错误:没有这样的主机:%s\n”,argv[1]);
返回2;
}
sockfd=套接字(AF_INET、SOCK_STREAM、IPPROTO_TCP);
如果(sockfd<0)syserr(“无法打开套接字”);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr=*((_addr*)服务器中的结构->h_addr);
serv_addr.sin_port=htons(端口号);
if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
syserr(“无法连接到服务器”);
printf(“已建立到%s:%s的连接。正在等待命令…\n\n\n”,argv[1],argv[2]);
做{
printf(“%s:%s>”,argv[1],argv[2]);//提示用户输入命令
fgets(缓冲区,255,标准输入);
n=strlen(缓冲区);
如果(n>0&&buffer[n-1]='\n')
缓冲区[n-1]='\0';
if(strcmp(buffer,“ls remote”)==0{//显示服务器目录中的文件
uint32_t尺寸;
uint32\u t commandSize=strlen(缓冲区);
//转换为网络形式
commandSize=htonl(commandSize);
n=send(sockfd,&commandSize,sizeof(commandSize),0);//将命令的大小发送到服务器
如果(n<0)syserr(“无法发送到服务器”);
n=send(sockfd,buffer,strlen(buffer),0);//向服务器发送命令
如果(n<0)syserr(“无法发送到服务器”);
n=recv(sockfd,&size,sizeof(size),0);//接收目录的大小
如果(n<0)syserr(“无法从服务器接收”);
尺寸=ntohl(尺寸);
int currentSize=0;
printf(“服务器上的文件:%s\n”,argv[1]);
while(当前大小<大小){
memset(&buffer[0],0,sizeof(buffer));
n=recv(sockfd,buffer,255,0);//从服务器接收目录
如果(n<0)syserr(“无法接收服务器”);
currentSize=currentSize+n;
printf(“%s”,缓冲区);
}
}
else if(strcmp(buffer,“ls local”)==0){//显示本地目录中的文件
printf(“客户端的文件:\n”);
readDirectory();
}
else if(strncmp(buffer,“get”,4)==0){//download来自服务器的文件
如果(strlen(buffer)<5){//没有输入文件
printf(“%s\n”,“错误…缺少文件名:get”);
}
否则{
uint32_t文件大小;
uint32\u t commandSize=strlen(缓冲区);
//转换为网络形式
commandSize=htonl(commandSize);
n=send(sockfd,&commandSize,sizeof(commandSize),0);//将命令的大小发送到服务器
如果(n<0)syserr(“无法发送到服务器”);
n=send(sockfd,buffer,strlen(buffer),0);//向服务器发送命令
如果(n<0)syserr(“无法发送到服务器”);
n=recv(sockfd,&fileSize,sizeof(fileSize),0);//获取文件大小
如果(n<0)syserr(“无法从服务器接收”);
fileSize=ntohl(fileSize);
如果(文件大小==-1){
printf(“%s\n”,“文件不存在”);
}
否则{//文件存在
int totalBytes=0;
int字节数=0;
//获取文件名
char*fileName=strtok(缓冲区“”);
fileName=strtok(NULL,“”);
memcpy(临时,文件名,strlen(文件名));//将文件名复制到临时
临时文件[strlen(文件名)]='\0';
//创建具有给定名称的新文件
FILE*fpNew=fopen(文件名,“w”);
如果(fpNew){
while(总字节<文件大小){
//接收字节
n=recv(sockfd,buffer,sizeof(buffer),0);
如果(n<0)syserr(“无法从服务器接收”);
//写入字节
intb=fwrite(缓冲区,1,n,fpNew);
if(b<0)
syserr(“错误写入文件”);
如果(n==0){//在服务器端读取时出错
打破
}
totalBytes=n+totalBytes;
字节写入=b+字节写入;
}
fclose(fpNew);
if(bytesWrited==fileSize)//成功读取/写入文件的所有字节
printf(“检索文件%s:成功。\n”,临时文件);
其他的
printf(“检索文件%s:不成功。\n”,临时文件);
}
否则{
syserr(“无法打开文件进行写入”);
}
}
}
}
else if(strncmp(缓冲区,“put”,4)=0){//将文件上载到服务器
if(strlen(缓冲区)<5){
printf(“%s\n”,“错误…缺少文件名:get”);
}
否则{
uint32\u t commandSize=strlen(缓冲区);
#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] = '\0';
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");