所以我有服务器/客户端应用程序正在运行。到目前为止,我可以很好地与服务器通信。我可以让它处理ls
命令,以便客户端获取文件列表。在这里,我偶然发现了一个问题,我想在服务器中键入各种命令,如cd ..
,mv
,cp
或cd directory
,以便服务器可以处理它们,客户端会获得有关这些行动的反馈。我认为代码会介于这些行之间:
message_size = recv(socket_fd, input, sizeof(input)/sizeof(input[0]), 0);
if(message_size > 0) {
/* Process incoming message, add end of the line sign */
input[message_size] = '\0';
/* Process command and get a response from it */
fp = popen(input, "r");
if(fp == NULL)
fprintf(stderr, "popen() failed: %s\n", strerror(errno));
else {
// IS THIS THE RIGHT APPROACH??
if(strcmp(input, "ls") == 0) {
while((c = getc(fp)) != EOF) {
output[i] = c;
i++;
}
i = 0;
send_message(socket_fd, output);
}
else if(strcmp(input, "cd ..") == 0) {
send_message(socket_fd, "cd ..");
}
}
pclose(fp);
快速解释:input
是服务器从客户端收到的内容。这可以是cd ..
。 send_message
只是向客户发送一些信息的功能 - 没什么大不了的。 fp
是一种FILE *
如何解除各种命令,从中获取反馈,尤其是 - 从asdf
等客户端获取有关插入错误的命令的反馈。我的想法是使用strcmp
我可以在客户端上进行各种处理,但出于某种原因,当我输入ls
时,我的客户端会冻结。
客户代码:
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#define MAX_SIZE 10000
int main(int argc, char* argv[])
{
int socket_fd, port_number;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[MAX_SIZE];
int rc;
if(argc<2) {
fprintf(stderr,"Incorrect arguments input\n");
exit(0);
}
port_number = 12345;
server = gethostbyname(argv[1]);
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
perror("Error opening socket");
exit(1);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_number);
bcopy((char*) server->h_addr,(char *) &serv_addr.sin_addr.s_addr,sizeof(server->h_length));
if(connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Error connecting");
exit(1);
}
enum {
INIT_STATE,
READY_STATE
} serv_state = INIT_STATE;
#define check_serv_state(str, st) \
(strncmp(str, #st, sizeof(#st) - 1) == 0)
for(;;) {
memset(buffer, 0, sizeof(buffer));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
if(rc<0) {
perror("Error reading back from server");
exit(1);
}
else if(rc == 0) {
printf("The server has been disconnected. Quitting.\n");
exit(0);
}
if(serv_state == INIT_STATE) {
char *part = strtok(buffer,"\n");
do {
if(check_serv_state(part, READY)) {
printf("Server is ready\n");
serv_state = READY_STATE;
}
else
printf("Server: [[[%s]]]\n", part);
} while((part = strtok(NULL, "\n")));
if(serv_state != READY_STATE)
continue;
} else
printf("#server: %s", buffer);
memset(buffer, 0, sizeof(buffer));
printf("#client: ");
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if(send(socket_fd, buffer, strlen(buffer), 0) < 0)
{
perror("Error sending message");
exit(1);
}
}
close(socket_fd);
return 0;
}
修改
正如@Olaf Dietsche所说那是fgets
错。现在我想知道为什么服务器不处理cd ..
命令。
答案 0 :(得分:1)
除非您的服务器发送一些欢迎消息,否则客户端会冻结&#34;,因为它等待来自服务器的输入
for (;;) {
memset(buffer, 0, sizeof(buffer));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
同时,服务器正在等待来自客户端的输入。所以两人都在等待。这就是为什么没有进展的原因。
要解决此问题,您必须先读取用户的输入,然后将此输入从客户端发送到服务器。例如。将其从循环结束移动到循环的开头
printf("#client: ");
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if (send(socket_fd, buffer, strlen(buffer), 0) < 0) {
perror("Error sending message");
exit(1);
}
另一个问题可能是fgets
如果文件结束或找到换行符,则解析停止,在这种情况下str将包含该换行符。
由于您发送整个缓冲区,包括最终换行符,服务器也必须检查此换行符
if (strcmp(input, "ls\n") == 0) {
或者,您可以在将请求发送到服务器之前将其删除
fgets(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, stdin);
int len = strlen(buffer);
if (buffer[len - 1] == '\n') {
buffer[len - 1] = 0;
--len;
}
if (send(socket_fd, buffer, len, 0) < 0) {
cd
命令在某种意义上是特殊的,它只更改调用进程中的目录。使用popen
时,命令将由子进程处理
popen()函数通过创建管道,分叉和调用shell来打开一个进程 ...
command参数是一个指向包含shell命令行的以null结尾的字符串的指针。 使用-c标志将此命令传递给/ bin / sh;解释,如果有的话,由shell执行。
这意味着,服务器调用popen
,创建另一个进程,而另一个进程执行chdir
。
如果您希望服务器进程更改目录,则不能使用popen
,而是在服务器本身中执行chdir
。