В настоящее время я пишу примитивную клиент-серверную программу в 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 != '\0') {
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] = '\0';
message_sent[0] = '\0';
//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;
}
Client:
#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] = '\0';
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] = '\0';
rcv_message[0] = '\0';
}
close(client_retcode);
}
return 0;
}
Как может быть ясно, из кода я не очень хороший программист на C. При выполнении программы я добираюсь до того момента, когда клиент предоставляет имя пользователя, а сервер проверяет его достоверность. Проблема в том, что после этого она останавливается. Если имя пользователя действительно, ветвь else
на стороне клиента никогда не берется, и после этого ничего не происходит в соответствующих оболочках. Он работает очень хорошо, если я вынимаю все if-else
и не проверяю правильные имена пользователей, но это важная часть моей реализации, и я не могу обойтись без этого. Что я делаю не так?
@ JS1 Исправлено это, но до сих пор не решает проблему. –
_ «Если имя пользователя является допустимым, ветвь' else' на стороне клиента никогда не берется »_ Если' '' было достигнуто, и имя пользователя было бы действительным, будет выведена ветка 'else'. Таким образом, либо ваш компилятор не может получить простую форму if-else, либо 'if' никогда не будет достигнута. Я оставлю вас, чтобы выяснить, какая из этих возможностей более вероятна. Подсказка: много очень хороших программистов на C тоже используют ваш компилятор и заметили бы, если бы он не поддерживал if-else. –