- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是我第一次尝试使用 fork() 实现多宿主文件服务器(有点)。目的是处理以“创建删除打开关闭写入读取寻找-filetarget ...”形式发送操作的多个主机(例如创建-hello.c写入-hello.c删除-hello.c)。
服务器
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<ctype.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<sys/socket.h>
#define BACKLOG 10
extern int inet_ntoa();
extern int inet_pton();
int master(int, int);
int control(char []);
int execute(int, int, char [], char [], char[], int);
int main(int argc, char *argv[]){
int server, accepted, porta, nuovo;
struct sockaddr_in listener, client;
socklen_t len;
if(argc!=2){ //CONTROLLO PARAMETRI
printf("Errore nei parametri.\n");
return -1;
}else porta = atoi(argv[1]); //CONVERSIONE NUMERO DI PORTA
if((server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0){ //CREAZIONE DELLA SOCKET
perror("Errore nella creazione della socket.");
return -1;
}
memset(&listener, 0, sizeof(listener)); //SETTAGGIO ATTRIBUTI LISTENER
client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
listener.sin_port = htons(porta);
if(bind(server, (struct sockaddr *)&listener, sizeof(listener)) < 0){ //BINDING SERVER
perror("Errore binding!");
return -1;
}
if(listen(server, BACKLOG) < 0){ //LISTENING
perror("Errore listening!\n");
return -1;
}
printf("Socket inizializzata con successo..\n");
sleep(2);
system("clear");
while(1){
printf("FATHER: *** in attesa ***\n");
len = sizeof(client);
accepted = accept(server, (struct sockaddr *)&client, &len); //ACCETTO NUOVA CONNESIONE SU ACCEPTED
if(accepted < 0){
perror("Errore nella accept!");
return -1;
}
printf("FATHER: *** connessione stabilita con il client %d ***\n", inet_ntoa(client.sin_addr));
nuovo = fork(); //FORK()
if(nuovo == 0){ //FIGLIO
master(accepted, server);
}else if(nuovo < 0){
perror("Errore fork!");
exit(-1);
}else close(accepted);
}
return 0;
}
int master(int accepted, int server){
int fd, i, k, j, flag;
char richiesta[256], operazione[256], result[256], file[256], file_opened[256];
printf("Figlio\n");
close(server); //CHIUDO SERVER CHE HO EREDITATO E NON MI SERVE
recv(accepted, richiesta, sizeof(richiesta), 0); //RICEVO RICHIESTA
//printf("Richiesta -> %s", richiesta);
if(strcmp(richiesta,"exit") == 0){ //SE RICHIESTA DI USCITA, ESCO
close(accepted);
exit(0);
}
fd = -1; //AZZERO GLI INDICI E PONGO IN STATO DI ERRORE fd
j = 0;
k = 0;
i = 0;
while(i < strlen(richiesta)){ //FINCHÈ LA RICHIESTA NON È STATA ESAMINATA PER INTERO
while(richiesta[i] != '-'){ //FINCHÈ NON INCONTRO UN CARATTERE "-"
operazione[j] = richiesta[i]; //COPIO OGNI LETTERA DI RICHIESTA IN OPERAZIONE
j++;
i++;
}
operazione[strlen(operazione) - 1] = '\0'; //TERMINO LA STRINGA CON '\0'
i = i+1; //AVANZO DI UNO SUPPONENDO DI TROVARMI SU UNO SPAZIO
while(richiesta[i] != ' '){ //FINCHÈ NON TROVO UN ALTRO SPAZIO
file[k] = richiesta[i]; //COPIO OGNI LETTERE DI RICHIESTA IN FILE
i++;
k++;
}
if(!isalpha(file[strlen(file) - 1]))file[strlen(file) - 1] = '\0'; //TERMINO LA STRINGA CON '\0'
flag = control(operazione); //CONTROL VERIFICA LA VALIDITÀ
if(flag == -1) strcpy(result,"Errore nella richiesta!\n\0"); //SE ERRORE, RESULT CONTERRÀ IL MESSAGGIO DI ERRORE
else execute(flag, fd, result, file, file_opened, accepted); //ALTRIMENTI SI PROCEDE CON L'ESECUZIONE DI QUANTO CHIESTO
send(accepted, result, sizeof(result), 0); //SENDO IL RISULTATO
memset(result, '\0', sizeof(result)); //AZZERO LE STRINGHE ED I CONTATORI UTILIZZATE
memset(file, '\0', sizeof(file));
memset(operazione, '\0', sizeof(operazione));
j = 0;
k = 0;
}
send(accepted, "end", sizeof("end"), 0); //NOTIFICO LA FINE DELL'ESECUZIONE E CHIUDO
close(accepted);
printf("Fine figlio\n");
exit(0);
}
int control(char operazione[]){
if((strcmp(operazione,"write"))==0) return 1;
else if((strcmp(operazione,"read"))==0) return 2;
else if((strcmp(operazione,"seek"))==0) return 3;
else if((strcmp(operazione,"open"))==0) return 4;
else if((strcmp(operazione,"close"))==0) return 5;
else if((strcmp(operazione,"delete"))==0) return 6;
else if((strcmp(operazione,"create"))==0) return 7;
else return -1;
}
int execute(int flag, int fd, char result[], char file[], char file_opened[], int client_descriptor){
char testo[8192], off[5];
int offset;
char operation[3][6] = {"read\0", "write\0", "seek\0"};
char noop[] = "noop";
if(fd != -1){
if(strcmp(file_opened, file) != 0){
strcpy(result,"Errore, il file aperto non è quello sul quale si vuole operare!\n\0");
return -1;
}
}
switch(flag){
case 1: //write
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[1], strlen(operation[1]), 0); //ask for text over network
recv(client_descriptor, testo, sizeof(testo), 0);
while(lockf(fd, F_TEST, 0) != 0);
lockf(fd, F_LOCK, 0);
write(fd, testo,sizeof(testo));
lockf(fd, F_ULOCK, 0);
memset(testo, '\0', sizeof(testo));
}
break;
case 2: //read
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[0], strlen(operation[0]), 0);
while(read(fd, testo, sizeof(testo)) > 0) send(client_descriptor, testo, strlen(testo), 0);
}
break;
case 3: //seek
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[2], strlen(operation[2]), 0);
recv(client_descriptor, off, sizeof(off), 0);
offset = atoi(off);
while(lockf(fd, F_TEST, 0) != 0);
lockf(fd, F_LOCK, 0);
lseek(fd, (long int)offset, SEEK_SET);
lockf(fd, F_ULOCK, 0);
}
break;
case 4: //open
send(client_descriptor, noop, sizeof(noop), 0);
if(fd == -1){
if((fd = open(file, O_RDWR))<0){
strcpy(result,"Errore, file inesistente!\n\0");
return -1;
}else strcpy(file_opened, file);
}else{
strcpy(result,"Errore, un file è già aperto!\n\0");
return -1;
}
break;
case 5: //close
send(client_descriptor, noop, sizeof(noop), 0);
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
close(fd);
memset(file_opened, '\0', strlen(file_opened));
}
break;
case 6: //delete
send(client_descriptor, noop, sizeof(noop), 0);
if(strcmp(file_opened, file) == 0){
strcpy(result,"Errore, il file da eliminare è attualmente aperto!\n\0");
return -1;
}else if(remove(file) < 0){
strcpy(result,"Errore, il file da eliminare non esiste!\n\0");
return -1;
}
break;
case 7: //create
send(client_descriptor, noop, sizeof(noop), 0);
if(open(file, O_CREAT)<0){
strcpy(result,"File inestente, creane uno prima di scriverci!\n\0");
return -1;
}
break;
}
strcpy(result,"\nSuccesso!\n\0");
return 0;
}
服务器创建一个监听套接字,接受一个新连接,fork()本身,父亲返回监听, child 为客户端服务。具体来说,子进程接收客户端请求并将其分成两部分:operazione[](要执行的操作)和 file[](目标)。然后控制它们并执行操作。重复直到请求字符串终止。
客户端
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
extern int inet_pton();
int main(int argc, char *argv[]){
int server, porta;
struct sockaddr_in addr;
char result[256], richiesta[256], risposta[256], testo[8192];
socklen_t len;
if(argc!=3){ //CONTROLLO I PARAMETRI
printf("Errore nei parametri.\n");
return -1;
}else porta = atoi(argv[2]); //CONVERTO IN NUMERO LA PORTA
if((server = socket(AF_INET, SOCK_STREAM, 0))<0){ //CREAZIONE SOCKET
perror("Errore nella creazione della socket.");
return -1;
}
memset(&addr, 0, sizeof(addr)); //AZZERO LA STRUTTURA
addr.sin_family = AF_INET; //SETTAGGIO ATTRIBUTI STRUTTURA
addr.sin_port = htons(porta);
if((inet_pton(AF_INET, argv[1], &addr.sin_addr))<0){
printf("Settaggio attributi fallito.\n");
return -1;
}
len = sizeof(addr); //LUNGHEZZA IN BYTE DELLA STRUTTURA
if((connect(server, (struct sockaddr *)&addr, len))<0){ //CONNESSIONE AL SERVER
perror("Connessione fallita.");
return -1;
}
printf("Connessione stabilita!\n");
while(1){ //PER SEMPRE
sleep(2);
system("clear"); //PULISCI SCHERMO
memset(richiesta, '\0', sizeof(richiesta)); //AZZERAMENTO RICHIESTA
memset(risposta, '\0', sizeof(risposta)); //AZZERAMENTO RISPOSTA
do{
printf("SUPPORTATE (read write seek open close delete create) -file ...\n");
printf("Richiesta: ");
}while((fgets(richiesta, sizeof(richiesta), stdin)) == NULL);
printf("RICHIESTA %s\n", richiesta);
printf("Hey"); //ACQUISISCO RICHIESTA
if(strcmp(richiesta,"exit") == 0){ //SE È UGUALE ALLA STRINGA "exit", ESCE DAL CICLO
send(server, "exit\0", 5, 0); //SENDO "exit" AL SERVER
close(server); //CHIUDO LA CONNESSIONE
return 0;
}
printf("HELLO");
send(server, richiesta, strlen(richiesta), 0); //SENDO RICHIESTA
while(1){
while(recv(server, risposta, sizeof(risposta), 0) == 0); //RICEVO LA PRIMA RISPOSTA
if(strcmp(risposta,"end") == 0) break; //RICHIESTA PROCESSATA PER INTERO
if((strcmp(risposta,"read") == 0) || (strcmp(risposta,"write") == 0) || (strcmp(risposta,"seek") == 0)){ //SE LA RISPOSTA È UGUALE A "read", "write" O "seek"
memset(testo, '\0', sizeof(testo)); //AZZERO TESTO
if(strcmp(risposta,"read") == 0){ //SE È UGUALE A "read"
while(recv(server, testo, sizeof(testo), 0) > 0){ //LEGGO TUTTO E STAMPO A VIDEO
printf("%s", testo);
memset(testo, '\0', sizeof(testo));
}
}else if(strcmp(risposta,"write") == 0){ //SE È UGUALE A "write"
printf("Testo da scrivere sul file: ");
scanf("%s", testo);
send(server, testo, sizeof(testo), 0); //ACQUISISCO IL TESTO E LO MANDO AL SERVER
}else if(strcmp(risposta,"seek") == 0){ //SE È UGUALE A "seek"
printf("Numero di byte spostamento dall'inizio del file: ");
scanf("%s", testo); //ACQUISISCO NUMERO BYTE E SENDO
send(server, testo, sizeof(testo), 0);
}
}
recv(server, result, sizeof(result), 0);
printf("RESULT %s\n", result); //STAMPO LA RISPOSTA & AZZERO LA RISPOSTA
memset(risposta, '\0', sizeof(risposta));
memset(result, '\0', sizeof(result));
}
}
return 0;
}
客户端应向服务器发送请求,在需要时发送更多文本(例如写入或查找)并在需要时显示它(例如读取),然后显示服务器发送的操作状态(成功或错误)执行。
我的问题是,在客户端中输入请求后,它似乎被卡住并且什么都不做。没有显示诸如“Hey”或“Hello”之类的控件 printf。如果我将 while(recv(server, risposta, sizeof(risposta), 0) == 0);
替换为 recv(server, risposta, sizeof(risposta), 0); ,就会出现这种情况
但随后它开始循环,就好像 recv() 不阻塞一样。
哪里有错误?我要疯了。
最佳答案
如果不将 recv()
的结果存储到变量中并对其进行测试 (i) -1(表示错误),(ii) 0(表示对等点),则无法编写正确的网络代码已关闭连接,或 (iii) 正数,表示您实际收到的字节数。如果 (i) 您需要打印或记录错误,请关闭套接字并退出;在情况 (ii) 中,您需要关闭套接字并退出。
您也不能假设整个请求都是在单个 recv()
中接收的:您必须循环;或者由任何单个 recv()
操作产生的缓冲区以 null 终止。
您还需要测试 send()
的结果:您不能仅仅假设它成功了。
修复所有这些问题并重试。
关于c - 多宿主 TCP 服务器和客户端陷入循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40901420/
我是 ZMQ 的新手。我发现 ZMQ 套接字实现比 winsock 简单得多。但我怀疑 “使用 ZMQ TCP 套接字创建的客户端可以与传统的 TCP 服务器通信吗?” 换句话说我的 ZMQ 客户端可
我想使用 TCP 协议(protocol) 将数据发送到 Logstash。为了发送数据,我正在使用 Node-RED。一个简单的配置如下所示: 在 Logstash 文件夹中,我创建了一个名为 no
当我尝试更改窗口缩放选项时,作为 root,我可以通过在 /proc/sys/net/中执行 net.ipv4.tcp_mem=16777000 来更改值。如果我必须更改这 100 个系统,那将需要大
明天做一些练习题,这道做不出来 TCP 服务器连接 TCP 客户端进行通信所需的最小套接字端口数是多少? 肯定只有两个吧?一个用于服务器,一个用于客户端,但这似乎是显而易见的。我的伙伴们认为 TCP
考虑一个存在一个服务器和多个客户端的场景。每个客户端创建 TCP 连接以与服务器交互。 TCP alive的三种用法: 服务器端保活:服务器发送 TCP 保活以确保客户端处于事件状态。如果客户端死了,
TCP TAHOE 和 TCP RENO 有什么区别。 我想知道的是关于 3-dup-ack 和超时的行为? SST 发生了什么变化? 谢谢! 最佳答案 TCP Tahoe 和 Reno 是处理 TC
大家早上好。我一直在阅读(其中大部分在堆栈溢出中)关于如何进行安全密码身份验证(散列 n 次,使用盐等)但我怀疑我将如何在我的 TCP 客户端中实际实现它-服务器架构。 我已经实现并测试了我需要的方法
在遍历 RFC793 时,我开始知道应该以这种方式选择初始序列号段重叠被阻止。 有人能解释一下如果发生重叠,重复段将如何影响 TCP? 最佳答案 不同的操作系统有不同的行为。参见 http://ins
你能举例说明一下tcp/ip中nagle算法的概念吗? 最佳答案 我认为Wikipedia在开头的段落中做得很好。 Nagle's document, Congestion Control in IP
似乎最大 TCP 接收窗口大小为 1GB(使用缩放时)。因此,仍然可以用一个连接填充 100Gb 管道的最大 RTT 是 40ms(因为 2 * 40E-3 * 100E9/8 = 1GB)。这会将这
考虑在两个 TCP 端点之间建立的 TCP 连接,其中一个调用: 关闭():此处,不允许进一步读取或写入。 关机(fd,SHUT_WR):这会将全双工连接转换为单工连接,其中调用 SHUT_WR 的端
我是在 Lua 中编写解析器的新手,我有两个简短的问题。我有一个包含 TCP 选项的数据包,如 MSS、TCP SACK、时间戳、NOP、窗口比例、未知。我基本上是在尝试剖析 TCP 选项字段中的未知
TCP 是否不负责通过在传输过程中发生丢失等情况时采取任何可能必要的措施来确保通过网络完整地发送流? 它做的不对吗? 为什么更高的应用层协议(protocol)及其应用程序仍然执行校验和? 最佳答案
考虑使用 10 Mbps 链路的单个 TCP (Reno) 连接。假设此链路不缓冲数据并且接收方的接收缓冲区比拥塞窗口大得多。设每个 TCP 段的大小为 1500 字节,发送方和接收方之间连接的双向传
考虑这样一个场景,有client-a和server-b。 server-b 禁用了 TCP keepalive。 server-b 没有任何应用程序逻辑来检查 TCP 连接是否打开。 client-a
我正在尝试用 Rust 编写回显服务器。 use std::net::{TcpStream, TcpListener}; use std::io::prelude::*; fn main() {
听说对于TCP连接,服务器会监听一个端口,并使用另一个端口发送数据。 例如,Web 服务器监听端口 80。每当客户端连接到它时,该服务器将使用另一个端口(比如 9999)向客户端发送数据(Web 内容
我试图了解带有标记 PSH 和标记 URG 的 TCP 段之间的区别。我阅读了 RFC,但仍然无法理解,其中一个在将数据发送到进程之前缓冲数据而另一个没有吗? 最佳答案 它们是两种截然不同的机制。 #
有第三方服务公开 TCP 服务器,我的 Node 服务器(TCP 客户端)应使用 tls Node 模块与其建立 TCP 连接。作为 TCP 客户端, Node 服务器同时也是 HTTP 服务器,它应
我正在发送一些 TCP SYN 数据包以获得 TCP RST 的返回。为了识别每个探测器,我在 TCP 序列字段中包含一个计数器。我注意到以下几点: 当SYN probe中的sequence numb
我是一名优秀的程序员,十分优秀!