- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我目前正在用 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;
}
客户:
#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
分支将永远不会被采用,之后在相应的 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");
}
...
}
如果用户名有效,您的服务器不会返回任何响应,只是等待。如果用户名有效,您的服务器需要响应,否则您的客户端将永远等待在 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 - 不采用else分支的多线程代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28129725/
考虑以下代码: template struct list { template list(Args...) { static_assert(sizeof..
考虑以下代码: template struct list { template list(Args...) { static_assert(sizeof..
最近才开始学习"new"OpenGL(可编程而不是固定功能,我从 Nehe 教程中学到的),我想知道自从 OpenGL 4 发布以来学习 OpenGL 3 是否真的有用。 我问的原因是因为我想知道能够
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我想了解如何操作特征向量/矩阵。我想实现最小二乘高斯牛顿算法(因此我学习使用 Eigen 库)。我有一个 1x6 的参数 vector ,每次迭代都需要更新它们。现在,我只想弄清楚函数如何将 vect
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 5 年前。 Improv
我发现编写适用于Enums的静态方法非常困难。这是一个非常人为的示例,但假设您想要编写一个方法,该方法采用 Enum 常量并返回下一个声明的常量。我发现(大约一个小时后)你可以按如下方式进行。它可以工
我正在尝试编写一个函数,在某些条件下,将指向结构的指针更改为指向不同的结构。 我的限制是我想保留初始函数签名,该签名将指向指针(而不是特定结构类型)的通用指针作为参数。 这行不通: [nav] In
我正在尝试将 Keras 示例改编为 VAE https://blog.keras.io/building-autoencoders-in-keras.html 我修改了代码,使用有噪声的 mnist
自 JPA 2.0 以来,关系上有 orphanRemoval 属性,它极大地简化了父子关系的更新,并且与级联删除一起允许删除树的整个分支并轻松删除它。 但是,也有一些情况可能被标记为“收养”,即您将
我正在尝试编写一个类,它能够在以后及时调用不带参数的 lambda。我期待 C++17 类模板参数推导以避免需要工厂函数。但是,尝试在不指定类型的情况下实例化对象会失败。我可以很好地使用工厂功能,但我
我怎样才能避免并非所有控制路径都在此处返回容器的事实: enum Type {Int, String}; Container containerFactory(Type
我开始学习 C++ 和 STL。 我有一个问题: 写一个函数模板palindrome,接受一个 vector 参数并返回true或false来检查 vector 是否是回文(12321是回文,1234
我一直在尝试获取一个条目值(代码中的 S1)以将其自身设置为一个值(_attributes 字典中的 STR),但我就是无法让它工作。我想让它成为一个最终的顶层循环,但我在这方面一步一步来,因为我是一
我想做同样的事情 How do I get the number of days between two dates in JavaScript? 但我想对此日期格式执行相同操作:2000-12-31
我想编写一个带有构造函数的 C++ 类,该构造函数将 auto_ptr 作为其参数,以便我可以将类实例从 auto_ptr 初始化为另一个实例: #include class A { public:
我需要一种方法,我可以在其中获取二维数组中的输入并以最快的方式之一对其进行逐行排序。我尝试使用 Insertion Sort 同时获取 Input 和 Sort it。我使用的第二件事是我单独为一行取
好的,我已经阅读了一些关于 IDisposable 最佳实践的文章,我想我基本上明白了(终于)。 我的问题与从 IDisposable 基类继承有关。我看到的所有示例都在子类中一遍又一遍地编写相同的代
定义类时,以下是否有效? T(const T&&) = default; 我正在阅读移动构造函数 here并且它解释了如何仍然可以隐式声明默认值: A class can have multiple
我想使用 LoadLibrary 开发一个插件系统。 我的问题是:我希望我的函数采用 const char* 而 LoadLibrary 采用 LPCTSTR。 我有一个聪明的想法来做(LPCSTR)
我是一名优秀的程序员,十分优秀!