我正在用 C 语言开发一个 Unix 应用程序,该应用程序包含一个必须同时与最多五个客户端通信的服务器。客户端向服务器发送一个命令,该命令可以是tuttomaiuscolo(英文的alltoupper)
或tuttominuscolo(alltolower)
和一个要操作的字符串;服务器接收到这两个字符串并从第二个单词中删除所有不是 a-z A-Z
字符的字符。如果客户端发送字符串 FINE (end)
,则服务器必须停止并死亡(不会留下僵尸进程)。
问题出在客户端和服务器之间的连接上。为此,我在服务器和客户端中也使用了函数 select
,但问题是 select
放置在服务器(监视读数)中没有看不到客户端请求,因此它永远不会进入 accept
函数,而客户端 select
(监视写入)返回一个值,表示它已准备好写入。
现在我将发布代码:
服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include <ctype.h>
void ripulisci (char* stringa);
void minuscola (char* orig, char* dest);
void maiuscola (char* orig, char* dest);
void handler(int);
int list;
int sock;
int main () {
int status;
//creo un socket da mettere in ascolto
list = socket (AF_INET, SOCK_STREAM, 0);
if (list < 0) {
perror("Error!");
exit(1);
}
//preparo la struct sockaddr_in
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(2770);
//effettuo il bind
status = bind(list, (struct sockaddr*) &address, sizeof(address));
if (status < 0) {
perror("Error!");
close(list);
exit(1);
}
//mi metto in ascolto
listen(list, 1);
printf("Attendo le connessioni...\n");
//preparo le variabili necessarie per gestire i figli
int esci = 1;
pid_t server[5];
char comando[15];
char lettura[512];
char scrittura[512];
struct sockaddr_in client;
int client_size = sizeof(client);
fd_set fd;
FD_ZERO(&fd);
FD_SET(list, &fd);
struct timeval timer;
//genero i quattro figli/server e mi salvo i pid in un array
int index;
for (index=0 ; index<5 ; index++) {
server[index] = fork();
if (server[index] == 0)
break;
}
//verifico quale processo sono
if (index == 5) {
pause(); //aspetto un segnale da uno dei figli
}
//sono un figlio/server
else {
while(esci) {
timer.tv_sec = 1;
timer.tv_usec = 0;
if (select(list+1, &fd, NULL, NULL, &timer) <= 0) {
printf("Nessun client da servire\n");
continue;
}
if (!FD_ISSET(list, &fd))
continue;
printf("C'è un client\n");
sock = accept(list, (struct sockaddr*) &client, (socklen_t*) &client_size);
if (sock < 0)
break;
printf("Connesso con il client\n");
recv(sock, comando, 15, 0);
recv(sock, lettura, 512, 0);
if (comando[0] == 'F' && comando[1] == 'I' && comando[2] == 'N' && comando[3] == 'E' && comando[4] == '\0')
kill(getppid(), SIGALRM); //al termine dell'esecuzione uscirò
ripulisci(lettura);
//il comando è tuttomaiuscole
if (strcmp("tuttomaiuscolo", comando) == 0) {
maiuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//il comando è tuttominuscole
else if (strcmp("tuttominuscolo", comando) == 0) {
minuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//c'è stato un errore
else {
printf ("Error! Command not found\n");
strcpy (scrittura, "error");
send (sock, scrittura, 512, 0);
}
printf("Devo terminare!");
close(sock);
exit(0);
}
}
//termino tutto
for(index=0 ; index<5 ; index++) {
waitpid((int)server[index], NULL, 0);
}
exit(0);
}
void handler(int sig) {
signal(sig, SIG_IGN);
printf("Il server sta terminando in seguito ad una richiesta\n");
close (list);
close (sock);
exit(0);
}
void ripulisci (char* stringa) {
int index = 0;
int app;
while (stringa[index] != '\0' && index<=511) {
if (isalpha(stringa[index])!=1) {
app = index;
do {
stringa[app] = stringa[app+1];
app++;
} while (stringa[app] != '\0');
stringa[app] = '\0';
index--;
}
index++;
}
return;
}
void minuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] < 91)
dest[index] = toupper(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
void maiuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] > 91)
dest[index] = tolower(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
客户端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
int main () {
int descrittoreSocket;
descrittoreSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(2770);
address.sin_addr.s_addr = INADDR_ANY;
printf ("Connessione in corso...\n");
int ris;
ris = connect(descrittoreSocket, (struct sockaddr*) &address, (socklen_t) sizeof(address));
fd_set fd;
FD_ZERO(&fd);
FD_SET(descrittoreSocket, &fd);
struct timeval timer;
timer.tv_sec = 1;
timer.tv_usec = 0;
if ((ris > -1) && select(descrittoreSocket+1, NULL, &fd, NULL, &timer) >= 0 && FD_ISSET(descrittoreSocket, &fd)) {
printf ("Connessione avvenuta...\n");
char buffer_r [512];
char buffer_w [512];
char command [15];
gets(command);
gets(buffer_r);
send(descrittoreSocket, command, 15, 0);
printf("Spedito!");
fflush(stdout);
send(descrittoreSocket, buffer_w, 512, 0);
printf("Spedito!");
fflush(stdout);
recv(descrittoreSocket, buffer_r, 512, 0);
printf("Trasferito!");
fflush(stdout);
if (strcmp("error", buffer_r) == 0)
printf ("ERROR!");
printf ("%s", buffer_r);
fflush(stdout);
} else {
printf ("Impossibile servire il client\n");
}
close (descrittoreSocket);
exit(0);
}
语法高亮:
服务器:http://pastebin.com/5Nd96JxC
客户:http://pastebin.com/aSvR6qVM
如有需要,请随时要求澄清。
最佳答案
你的服务器不应该只使用一个监听套接字来使用select
...相反,它应该在监听套接字上监听客户端的连接,当有连接时,接受它,然后从套接字中读取客户端给出的命令。如果你想一次处理来自客户端的多个请求,那么你可以为每个接受的连接分拆一个单独的进程或线程。如果您想避免在监听套接字调用 accept
期间发生阻塞行为,那么您始终可以使用带有 FIONBIO
标志的 ioctl
监听套接字。
在客户端,我也没有看到需要 select
……同样,服务器上只有一个套接字可以通信。只需在服务器上打开一个连接,该连接将阻塞直到建立连接,建立该连接后,您就可以读取和写入服务器。
关于c - 在 C 中的客户端/服务器确认中使用 select(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8777055/