不采用else分支的多线程代码
Multithreaded code not taking else branch
我目前正在用 C 为 Linux 编写一个原始的客户端-服务器程序。服务器是多线程的。我分别为客户端和服务器编写了以下代码:
服务器(使用gcc -o -lpthreads server server.c
编译):
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
void lsfunc(char *path, char *buffer) {
int pointer = sprintf(buffer, "User ID\tGroup ID\tFilename\n");
int cx = 0;
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
mydir = opendir(path);
myfile = readdir(mydir);
while ((myfile = readdir(mydir)) != NULL) {
stat(myfile->d_name, &mystat);
cx = sprintf(buffer+pointer, "%lu\t%lu\t%s\n", (unsigned long int) mystat.st_uid, (unsigned long int) mystat.st_gid, myfile->d_name);
pointer += cx;
}
closedir(mydir);
}
void makedir(char *path, char *prompt) {
struct stat st = {0};
if (stat(path, &st) == -1) {
mkdir(path, 0700);
sprintf(prompt, "Directory successfully created");
}
else {
sprintf(prompt, "A folder with the same name already exists");
}
}
void fgetsfunc(char *path, char *buffer) {
FILE *fp = fopen(path, "r");
char ch;
int pointer = 0;
while ((ch = getc(fp)) != EOF) {
sprintf(buffer+pointer, "%c", ch);
pointer += 1;
}
fclose(fp);
}
void fputsfunc(char *path, char *buffer) {
int resultCode = 0;
FILE *fp = fopen(path, "w");
resultCode = fputs(buffer, fp);
if (resultCode == EOF) {
fprintf(stderr, "Failed to write.\n");
}
fclose(fp);
}
int authenticate(char *username) {
int error = 0;
if (*username != 'u') {
error = -1;
}
*username++;
while (*username != '[=10=]') {
if (!isdigit(*username)) {
error = -1;
}
*username++;
}
return error;
}
void *connectionHandler(void *socket_descriptor) {
int rcv_retcode, wrt_retcode, error_code;
int sock = *(int*)socket_descriptor;
char message_received[100], message_sent[10000];
char user[5];
char *greetings;
char *FAIL = "FAIL";
greetings = "Welcome user. Enter your username: ";
write(sock, greetings, strlen(greetings));
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
fprintf(stdout, "Client says: %s\n",message_received);
const char s[2] = " ";
const char n[2] = "\n";
char *token, *command, *path, *input;
//char writeBuff[1000];
token = strtok(message_received, s);
command = token;
if (strcmp(command, "exit") == 0) {
close(sock);
strncpy(message_sent, "Client logged out.", 10000);
}
else if (strcmp(command,"ls") == 0) {
token = strtok(NULL, s);
path = token;
lsfunc(path, message_sent);
}
else if(strcmp(command,"mkdir") == 0) {
token = strtok(NULL, s);
path = token;
makedir(path, message_sent);
}
else if(strcmp(command,"fgets") == 0) {
token = strtok(NULL, s);
path = token;
fgetsfunc(path, message_sent);
}
else if(strcmp(command, "fputs") == 0) {
token = strtok(NULL, s);
path = token;
token = strtok(NULL, n);
input = token;
printf("%s\n", input);
fputsfunc(path, input);
strncpy(message_sent, "Written to file", 10000);
}
if ((wrt_retcode = write(sock, message_sent, 10000)) == -1) {
perror("Write failed");
}
message_received[0] = '[=10=]';
message_sent[0] = '[=10=]';
//sleep(1);
}
close(sock);
}
int main(int argc, char* argv[]) {
int socket_retcode, bind_retcode, listen_retcode, acc_retcode, rcv_retcode, wrt_retcode;
char message_received[100], message_sent[10000];
struct sockaddr_in server, client;
if ((socket_retcode = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Failed to create socket");
return -1;
}
fprintf(stdout, "Socket created successfully\n");
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(4000);
char *server_add = inet_ntoa(server.sin_addr);
uint16_t port_num = ntohs(server.sin_port);
printf("The address of the server is: %s\nThe port number is: %d\n", server_add,port_num);
if ((bind_retcode = bind(socket_retcode, (struct sockaddr*)&server, sizeof(server))) == -1) {
perror("Bind failed");
return -1;
}
if((listen_retcode = listen(socket_retcode, 20)) == -1) {
perror("Listen failed");
return -1;
}
int c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while ((acc_retcode = accept(socket_retcode, (struct sockaddr*)&client, (socklen_t*)&c))) {
printf("Connection accepted\n");
if (pthread_create (&thread_id, NULL, connectionHandler, (void*)&acc_retcode) < 0) {
perror("Thread creation failed");
}
printf("Handler assigned\n");
}
if (acc_retcode < 0) {
perror("Accept failed");
return -1;
}
return 0;
}
客户:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine(char *prompt, char *buff, size_t sz) {
int ch, extra;
if (prompt != NULL) {
printf ("%s", prompt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL) {
return NO_INPUT;
}
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
buff[strlen(buff)-1] = '[=11=]';
return OK;
}
int main(int argc, char *argv[]) {
char IP[20], message[100], rcv_message[10000], filewriter_buffer[10000], check;
char greeting[100], username[5], user_auth[5];
int port_num, flag = 1;
int client_retcode, IP_retcode, message_retcode, cnct_retcode, send_retcode, rcv_retcode;
int logon_rcv, send_usr, user_rcv;
struct sockaddr_in r_server;
client_retcode = socket(AF_INET,SOCK_STREAM,0);
if (client_retcode == -1) {
perror("Failed to create socket.");
return -1;
}
if (getLine("Enter IP: ", IP, sizeof(IP)) != OK) {
fprintf(stderr, "No/Invalid IP provided.\n");
return -1;
}
fprintf(stdout, "Enter Port Number: ");
if (scanf("%d%c", &port_num, &check) != 2 || check != '\n') {
printf("Non-integer port provided.\n");
return -1;
}
r_server.sin_family = AF_INET;
r_server.sin_port = htons(port_num);
r_server.sin_addr.s_addr = inet_addr(IP);
cnct_retcode = connect(client_retcode, (struct sockaddr *)&r_server, sizeof(r_server));
if (cnct_retcode == -1) {
perror("Connect failed");
return -1;
}
fprintf(stdout, "Connection to server on %s:%d successful\n", IP, port_num);
while(1) {
logon_rcv = recv(client_retcode, greeting, 100, 0);
if (logon_rcv == -1) {
perror("Receive failed");
}
if (getLine(greeting, username, sizeof(username)) != OK) {
printf("No/Invalid input\n");
return -1;
}
send_usr = send(client_retcode, username, 5, 0);
if (send_usr == -1) {
perror("Send failed");
return -1;
}
user_rcv = recv(client_retcode, user_auth, 5, 0);
if (user_rcv == -1) {
perror("Receive failed");
return -1;
}
if (strcmp(user_auth, "FAIL") == 0) {
fprintf(stderr, "Wrong username. Exiting...\n");
break;
}
else {
if (getLine("Enter command: ", message, sizeof(message)) != OK) {
printf("No/Invalid command provided\n");
return -1;
}
if(strcmp(message, "exit") == 0) {
send_retcode = send(client_retcode, message, 100, 0);
if(send_retcode == -1) {
perror("Send failed");
return -1;
}
break;
}
send_retcode = send(client_retcode, message, 100, 0);
if(send_retcode == -1) {
perror("Send failed");
return -1;
}
rcv_retcode = recv(client_retcode, rcv_message, 10000, 0);
if (rcv_retcode == -1) {
perror("Receive failed");
return -1;
}
printf("Server says: %s\n", rcv_message);
message[0] = '[=11=]';
rcv_message[0] = '[=11=]';
}
close(client_retcode);
}
return 0;
}
从代码中可以清楚地看出,我不是一个很好的 C 程序员。执行程序时,我到了客户端提供用户名和服务器检查其有效性的地步。问题是:在那之后它停止了。如果用户名有效,则客户端的 else
分支将永远不会被采用,之后在各自的 shell 上也不会发生任何事情。如果我取出整个 if-else
并且不检查有效的用户名,它会工作得很好,但这是我实现的一个重要部分,我不能没有它。我做错了什么?
存在一些严重错误,但我认为您看到所述行为的原因是:
在server.c
中:
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
...
}
如果用户名有效,您的服务器不会return任何响应,只是等待。如果用户名有效,您的服务器需要响应,否则您的客户端将永远等待 client.c
:
/* Ends up waiting here forever */
user_rcv = recv(client_retcode, user_auth, 5, 0);
if (user_rcv == -1) {
perror("Receive failed");
return -1;
}
if (strcmp(user_auth, "FAIL") == 0) {
fprintf(stderr, "Wrong username. Exiting...\n");
break;
}
要解决此问题,请更改 server.c
(由注释指示):
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
write(sock, "butt", 5); /* Send something that isn't FAIL */
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
...
}
我目前正在用 C 为 Linux 编写一个原始的客户端-服务器程序。服务器是多线程的。我分别为客户端和服务器编写了以下代码:
服务器(使用gcc -o -lpthreads server server.c
编译):
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
void lsfunc(char *path, char *buffer) {
int pointer = sprintf(buffer, "User ID\tGroup ID\tFilename\n");
int cx = 0;
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
mydir = opendir(path);
myfile = readdir(mydir);
while ((myfile = readdir(mydir)) != NULL) {
stat(myfile->d_name, &mystat);
cx = sprintf(buffer+pointer, "%lu\t%lu\t%s\n", (unsigned long int) mystat.st_uid, (unsigned long int) mystat.st_gid, myfile->d_name);
pointer += cx;
}
closedir(mydir);
}
void makedir(char *path, char *prompt) {
struct stat st = {0};
if (stat(path, &st) == -1) {
mkdir(path, 0700);
sprintf(prompt, "Directory successfully created");
}
else {
sprintf(prompt, "A folder with the same name already exists");
}
}
void fgetsfunc(char *path, char *buffer) {
FILE *fp = fopen(path, "r");
char ch;
int pointer = 0;
while ((ch = getc(fp)) != EOF) {
sprintf(buffer+pointer, "%c", ch);
pointer += 1;
}
fclose(fp);
}
void fputsfunc(char *path, char *buffer) {
int resultCode = 0;
FILE *fp = fopen(path, "w");
resultCode = fputs(buffer, fp);
if (resultCode == EOF) {
fprintf(stderr, "Failed to write.\n");
}
fclose(fp);
}
int authenticate(char *username) {
int error = 0;
if (*username != 'u') {
error = -1;
}
*username++;
while (*username != '[=10=]') {
if (!isdigit(*username)) {
error = -1;
}
*username++;
}
return error;
}
void *connectionHandler(void *socket_descriptor) {
int rcv_retcode, wrt_retcode, error_code;
int sock = *(int*)socket_descriptor;
char message_received[100], message_sent[10000];
char user[5];
char *greetings;
char *FAIL = "FAIL";
greetings = "Welcome user. Enter your username: ";
write(sock, greetings, strlen(greetings));
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
fprintf(stdout, "Client says: %s\n",message_received);
const char s[2] = " ";
const char n[2] = "\n";
char *token, *command, *path, *input;
//char writeBuff[1000];
token = strtok(message_received, s);
command = token;
if (strcmp(command, "exit") == 0) {
close(sock);
strncpy(message_sent, "Client logged out.", 10000);
}
else if (strcmp(command,"ls") == 0) {
token = strtok(NULL, s);
path = token;
lsfunc(path, message_sent);
}
else if(strcmp(command,"mkdir") == 0) {
token = strtok(NULL, s);
path = token;
makedir(path, message_sent);
}
else if(strcmp(command,"fgets") == 0) {
token = strtok(NULL, s);
path = token;
fgetsfunc(path, message_sent);
}
else if(strcmp(command, "fputs") == 0) {
token = strtok(NULL, s);
path = token;
token = strtok(NULL, n);
input = token;
printf("%s\n", input);
fputsfunc(path, input);
strncpy(message_sent, "Written to file", 10000);
}
if ((wrt_retcode = write(sock, message_sent, 10000)) == -1) {
perror("Write failed");
}
message_received[0] = '[=10=]';
message_sent[0] = '[=10=]';
//sleep(1);
}
close(sock);
}
int main(int argc, char* argv[]) {
int socket_retcode, bind_retcode, listen_retcode, acc_retcode, rcv_retcode, wrt_retcode;
char message_received[100], message_sent[10000];
struct sockaddr_in server, client;
if ((socket_retcode = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Failed to create socket");
return -1;
}
fprintf(stdout, "Socket created successfully\n");
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(4000);
char *server_add = inet_ntoa(server.sin_addr);
uint16_t port_num = ntohs(server.sin_port);
printf("The address of the server is: %s\nThe port number is: %d\n", server_add,port_num);
if ((bind_retcode = bind(socket_retcode, (struct sockaddr*)&server, sizeof(server))) == -1) {
perror("Bind failed");
return -1;
}
if((listen_retcode = listen(socket_retcode, 20)) == -1) {
perror("Listen failed");
return -1;
}
int c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while ((acc_retcode = accept(socket_retcode, (struct sockaddr*)&client, (socklen_t*)&c))) {
printf("Connection accepted\n");
if (pthread_create (&thread_id, NULL, connectionHandler, (void*)&acc_retcode) < 0) {
perror("Thread creation failed");
}
printf("Handler assigned\n");
}
if (acc_retcode < 0) {
perror("Accept failed");
return -1;
}
return 0;
}
客户:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine(char *prompt, char *buff, size_t sz) {
int ch, extra;
if (prompt != NULL) {
printf ("%s", prompt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL) {
return NO_INPUT;
}
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
buff[strlen(buff)-1] = '[=11=]';
return OK;
}
int main(int argc, char *argv[]) {
char IP[20], message[100], rcv_message[10000], filewriter_buffer[10000], check;
char greeting[100], username[5], user_auth[5];
int port_num, flag = 1;
int client_retcode, IP_retcode, message_retcode, cnct_retcode, send_retcode, rcv_retcode;
int logon_rcv, send_usr, user_rcv;
struct sockaddr_in r_server;
client_retcode = socket(AF_INET,SOCK_STREAM,0);
if (client_retcode == -1) {
perror("Failed to create socket.");
return -1;
}
if (getLine("Enter IP: ", IP, sizeof(IP)) != OK) {
fprintf(stderr, "No/Invalid IP provided.\n");
return -1;
}
fprintf(stdout, "Enter Port Number: ");
if (scanf("%d%c", &port_num, &check) != 2 || check != '\n') {
printf("Non-integer port provided.\n");
return -1;
}
r_server.sin_family = AF_INET;
r_server.sin_port = htons(port_num);
r_server.sin_addr.s_addr = inet_addr(IP);
cnct_retcode = connect(client_retcode, (struct sockaddr *)&r_server, sizeof(r_server));
if (cnct_retcode == -1) {
perror("Connect failed");
return -1;
}
fprintf(stdout, "Connection to server on %s:%d successful\n", IP, port_num);
while(1) {
logon_rcv = recv(client_retcode, greeting, 100, 0);
if (logon_rcv == -1) {
perror("Receive failed");
}
if (getLine(greeting, username, sizeof(username)) != OK) {
printf("No/Invalid input\n");
return -1;
}
send_usr = send(client_retcode, username, 5, 0);
if (send_usr == -1) {
perror("Send failed");
return -1;
}
user_rcv = recv(client_retcode, user_auth, 5, 0);
if (user_rcv == -1) {
perror("Receive failed");
return -1;
}
if (strcmp(user_auth, "FAIL") == 0) {
fprintf(stderr, "Wrong username. Exiting...\n");
break;
}
else {
if (getLine("Enter command: ", message, sizeof(message)) != OK) {
printf("No/Invalid command provided\n");
return -1;
}
if(strcmp(message, "exit") == 0) {
send_retcode = send(client_retcode, message, 100, 0);
if(send_retcode == -1) {
perror("Send failed");
return -1;
}
break;
}
send_retcode = send(client_retcode, message, 100, 0);
if(send_retcode == -1) {
perror("Send failed");
return -1;
}
rcv_retcode = recv(client_retcode, rcv_message, 10000, 0);
if (rcv_retcode == -1) {
perror("Receive failed");
return -1;
}
printf("Server says: %s\n", rcv_message);
message[0] = '[=11=]';
rcv_message[0] = '[=11=]';
}
close(client_retcode);
}
return 0;
}
从代码中可以清楚地看出,我不是一个很好的 C 程序员。执行程序时,我到了客户端提供用户名和服务器检查其有效性的地步。问题是:在那之后它停止了。如果用户名有效,则客户端的 else
分支将永远不会被采用,之后在各自的 shell 上也不会发生任何事情。如果我取出整个 if-else
并且不检查有效的用户名,它会工作得很好,但这是我实现的一个重要部分,我不能没有它。我做错了什么?
存在一些严重错误,但我认为您看到所述行为的原因是:
在server.c
中:
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
...
}
如果用户名有效,您的服务器不会return任何响应,只是等待。如果用户名有效,您的服务器需要响应,否则您的客户端将永远等待 client.c
:
/* Ends up waiting here forever */
user_rcv = recv(client_retcode, user_auth, 5, 0);
if (user_rcv == -1) {
perror("Receive failed");
return -1;
}
if (strcmp(user_auth, "FAIL") == 0) {
fprintf(stderr, "Wrong username. Exiting...\n");
break;
}
要解决此问题,请更改 server.c
(由注释指示):
if((rcv_retcode = recv(sock, user, 5, 0)) == -1) {
perror("Receive failed");
}
error_code = authenticate(user);
if (error_code < 0) {
fprintf(stderr, "Failed to authenticate user.\n");
write(sock, FAIL, 5);
}
write(sock, "butt", 5); /* Send something that isn't FAIL */
while(1) {
if((rcv_retcode = recv(sock, message_received, 100, 0)) == -1) {
perror("Receive failed");
}
...
}