我有一个简单的问题。 我认为这很简单,至少!
我正在做一个大学项目,我已经构建了一个服务器 - 客户端即时消息服务,结构如下:
- 服务器创建 TCP套接字以侦听客户端请求
- 除了其他功能之外,每个客户端都可以使用UDP 向其他客户端(甚至是离线)发送消息
我已经将端口4242用于服务器,然后尝试将4243和4244用于两个示例客户端。
我的问题是:UDP通信不接受这些端口吗?
我问,因为当我尝试向这些端口发送消息时,接收客户端获取并打印“奇怪”的字符串
准确地说,就像存储先前的消息一样,首先打印新消息,然后打印一大堆先例消息。
另一方面,如果我使用例如4303和4486,它可以按预期工作。
我得到的那些数字看Wikipedia,但因为我不确定如何解释那个表(所以,如果我正确地解释它),因为我知道维基百科可能不那么可靠,我想我可以问这里。
另外,如果我提供的链接不可靠,是否有任何命令或资源可以检查这些内容?
提前致谢!
编辑:
这是我的代码!我之前无法上传..我也会试着给它做一个简短的解释 正如我在评论中提到的,我以为我有它,但是一个客户端没有收到来自另一个的消息。所以所有的工作,除了!发送功能,我猜...
客户端
客户端是用“!register username”连接到服务器的用户;这个命令:
- 如果客户是第一次连接到该服务,请将客户注册到该服务,当然还要将其设置为“在线”
- 如果客户已注册该服务,则重新连接客户端;在这种情况下,如果有一些离线消息,则服务器将其传递给te客户端
连接后,客户端可以使用以下命令:
1)!help:显示可用的命令
2)!who:显示在线用户
3)!取消注册:正如nam建议的那样,从服务器取消注册客户端
4)!发送用户名:如果目的客户端在线,则服务器返回UDP目的地址和端口,客户端直接发送消息;如果目标客户端处于脱机状态,则服务器会存储该消息,以便在连接后将其发送到目标客户端
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#define DIM 1024
#define ADDR_DIM 16
#define PORT_DIM 5
#define CMD_DIM 12
#define NAME_DIM 21
void cl_help(int sckt) {
int rv, length, l;
char* text = "!help";
char answer[DIM];
length = strlen(text);
l = htons(length);
//Sending command dimension
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Sending the command itself
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
}
void cl_quit(int sckt) {
int rv, length, l;
char* text = "!quit";
char answer[DIM];
length = strlen(text);
l = htons(length);
//Sending command dimension
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Sending the command itself
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
}
void cl_who(int sckt) {
int rv, length, l, n_net, n, i;
char* text = "!who";
char answer[DIM];
length = strlen(text);
l = htons(length);
//Sending the dimension of the command
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Sending the command itself
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
if( (strcmp(answer, "Nessun utente in linea") != 0)\
&& (strcmp(answer, "Devi essere connesso per poter utilizzare questa funzione") != 0) ) { //No user online; Yuo have to be registered
//Receiving number of users online
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) &n_net, length, 0);
if(rv < 0) {};
n = ntohs(n_net);
//Getting every username
for(i=0; i<n; i++) {
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
};
};
}
void cl_deregister(int sckt) {
int rv, length, l;
char* text = "!deregister";
char answer[DIM];
//Sending command dimension
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Receiving answer
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
}
void cl_register(int sckt, char* name, char* port) {
int rv, length, l, n, n_net, i;
char msg[DIM+NAME_DIM+4];
char answer[DIM];
sprintf(msg, "!register %s %s", name, port);
//Sending command
length = strlen(msg);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) msg, length, 0);
if(rv < 0) {};
//Receiving answer
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
if(strcmp(answer, "L'utente era gia' registrato al servizio: riconnessione completata.\n") == 0) { //Users already registered: reconnection
//Receiving info
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
if(strcmp(answer, "Messaggi offline presenti.") == 0) { //Offline messages found
//Receiving the number of messages
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) &n_net, length, 0);
if(rv < 0) {};
n = ntohs(n_net);
//Recevingi messages
for(i=0; i<n; i++) {
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) msg, length, 0);
if(rv < 0) {};
msg[length] = '\0';
puts(msg);
};
};
};
}
void cl_send(int sckt, int udp_sd, char* name, char* info, char* source) {
struct sockaddr_in dest;
int rv, length, l,p;
char msg[DIM+NAME_DIM+4];
char address[ADDR_DIM];
char port[PORT_DIM];
char answer[DIM];
char *pointer;
sprintf(msg, "!send %s", name);
//Sending command
length = strlen(msg);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) msg, length, 0);
if(rv < 0) {};
//Receiving answer
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
if(strcmp(answer, "Devi essere connesso per poter utilizzare questa funzione.\n") != 0) { //You have to be registered
if(strncmp(answer, "Client attualmente connesso", 27) == 0) { //User connected right now
pointer = answer+29; //to get only the address and the port number
sscanf(pointer, "%s %s", address, port);
address[ADDR_DIM] = '\0';
port[PORT_DIM] = '\0';
p = ntohs(atoi(port));
memset(&dest, 0, sizeof(dest));
memset(&msg, 0, sizeof(msg));f
//Destination UDP socket
dest.sin_family = AF_INET;
dest.sin_port = htons(p);
inet_pton(AF_INET, address, &dest.sin_addr);
//Sending direct message using UDP
sprintf(msg, "%s > ", source);
strcat(msg, info);
length = strlen(msg);
l = htons(length);
//Sending message
rv = sendto(udp_sd, (void*) &l, sizeof(l), 0, (struct sockaddr*) &dest, sizeof(dest));
if(rv < 0) {};
rv = sendto(udp_sd, (void*) msg, length, 0, (struct sockaddr*) &dest, sizeof(dest));
if(rv < 0) {};
} else { //Offline transmission: transmits message to server using TCP
length = strlen(info);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) info, length, 0);
if(rv < 0) {};
//Getting info from the server
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) answer, length, 0);
if(rv < 0) {};
answer[length] = '\0';
puts(answer);
};
};
}
int main(int argc, char* argv[]) {
struct sockaddr_in srv_addr;
struct sockaddr_in my_addr;
int sd, udp;
int err;
int pid;
int length, l;
char buffer[DIM];
char cmd[CMD_DIM];
char dest[NAME_DIM];
char my_name[NAME_DIM];
char in[DIM];
char to_send[DIM+NAME_DIM+4];
char part[DIM] = "";
if(argc != 5) {
//Check argument
exit(EXIT_FAILURE);
};
//TCP socket
sd = socket(AF_INET, SOCK_STREAM, 0);
//UDP socket
udp = socket(AF_INET, SOCK_DGRAM, 0);
//Pulizia
memset(&srv_addr, 0, sizeof(srv_addr));
memset(&my_addr, 0, sizeof(my_addr));
//TCP server parameters
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(atoi(argv[4]));
inet_pton(AF_INET, argv[3], &srv_addr.sin_addr);
//my UDP parameters
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET, argv[1], &my_addr.sin_addr);
//Bind for UDP socket
err = bind(udp, (struct sockaddr*) &my_addr, sizeof(my_addr));
if(err < 0) {};
//Connecting to the server
err = connect(sd, (struct sockaddr*) &srv_addr, sizeof(srv_addr));
if(err < 0) {};
//Auto-sending help command to display available operations
strcpy(cmd, "!help");
length = strlen(cmd);
l = htons(length);
err = send(sd, (void*) &l, sizeof(l), 0);
if(err < 0) {};
err = send(sd, (void*) cmd, length, 0);
if(err < 0) {};
//Receiving info from the server -> available operations
err = recv(sd, (void*) &l, sizeof(l), 0);
if(err < 0) {};
length = ntohs(l);
err = recv(sd, (void*) buffer, length, 0);
if(err < 0) {};
buffer[strlen(buffer)] = '\0';
puts(buffer);
pid = fork();
if(pid == 0) {
//Child
close(sd);
while(1) {
memset(to_send, 0, sizeof(to_send));
err = recvfrom(udp, (void*) &l, sizeof(l), 0, 0, 0);
if(err < 0) {
puts("error recvfrom");
exit(EXIT_FAILURE);
};
length = ntohs(l);
err = recvfrom(udp, (void*) to_send, length, MSG_WAITALL, 0, 0);
if(err < 0) {
puts("error recvfrom");
exit(EXIT_FAILURE);
};
to_send[length] = '\0';
puts(to_send);
};
} else {
//Parent
while(1) {
//Asking the user to prompt the command
memset(cmd, 0, sizeof(cmd));
memset(in, 0, sizeof(in));
memset(dest, 0, sizeof(dest));
puts("\nInserisci un comando: "); //Insert a command
fgets(in, DIM, stdin);
in[strlen(in)-1] = '\0';
sscanf(in, "%s", cmd);
cmd[CMD_DIM-1] = '\0';
if(strcmp(cmd, "!help") == 0) {
cl_help(sd);
continue;
};
if(strcmp(cmd, "!deregister") == 0) {
cl_deregister(sd);
};
if(strcmp(cmd, "!register") == 0) {
sscanf(in, "%s %s", cmd, dest);
cmd[CMD_DIM-1] = '\0';
dest[NAME_DIM-1] = '\0';
strcpy(my_name, dest);
if(strlen(dest) == 0) { //to avoid an empty username
puts("Errore: non hai inserito alcun username; riprova.\n"); //Please insert an username
} else {
cl_register(sd, dest, argv[2]);
};
continue;
};
if(strcmp(cmd, "!who") == 0) {
cl_who(sd);
continue;
};
if(strcmp(cmd, "!send") == 0) {
sscanf(in, "%s %s", cmd, dest);
cmd[CMD_DIM-1] = '\0';
dest[NAME_DIM-1] = '\0';
while(1) {
memset(part, 0, sizeof(part));
fgets(part, DIM-(strlen(to_send)-NAME_DIM-4), stdin);
l = strlen(part);
if((part[l-2] == '.') && (part[l-1] == '\n') && (strlen(part) == 2)) {
part[l-2] = '\0';
break;
} else {
strcat(to_send, part);
};
if(strlen(to_send) >= DIM+NAME_DIM+3) {
to_send[DIM+NAME_DIM+3] = '\0';
break;
};
};
strcat(to_send, "\0");
cl_send(sd, udp, dest, to_send, my_name);
memset(to_send, 0, sizeof(to_send)); //to empty the buffer used to store the message sent
continue;
};
if(strcmp(cmd, "!quit") == 0) {
cl_quit(sd);
close(sd);
break;
} else{
puts("Comando non valido.\n"); //Not a valid command
};
};
};
return 0;
}
服务器
服务器应答来自客户端的请求,并构建为并发服务器。
#include <sys/mman.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#define MAX_CONN 100
#define DIM 1024
#define ADDR_DIM 16
#define CMD_DIM 12
#define NAME_DIM 20
#define MSG_DIM DIM+NAME_DIM+4
#define PORT_DIM 5
#define MAX_UTN 1024
struct users {
char username[NAME_DIM];
char status; //c = connected, o = offline
struct sockaddr_in address;
char pendent[DIM][DIM];
char sender[DIM][NAME_DIM];
int msg; //last message to be sent
};
void srv_help(int sckt) {
int rv, length, l;
char* text = "Sono disponibili i seguenti comandi: \n\
!help --> mostra l'elenco dei comandi disponibili \n\
!register username --> registra il client presso il server\n\
!deregister --> de-registra il client presso il server\n\
!who --> mostra l'elenco degli utenti disponibili\n\
!send username --> invia un messaggio ad un altro utente\n\
(messaggio subito dopo comando\n\
!quit --> disconnette il client dal server ed esce\n\
('username': max 20 caratteri)\n\
(per terminare messaggio inserisci un . da solo)\n";//info about the available commands
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
};
void srv_who(int sckt, struct users* reg, int last) {
int i, rv, length, l;
char text[DIM];
strcpy(text, "Nessun utente in linea\n");//No user online
if(last == 0) { //if no user is online
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
} else {
strcpy(text, "Utenti in linea:\n"); //Users online:
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Here I send the number of users online, to synchronize server and client
length = sizeof(last);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
l = htons(last);
rv = send(sckt, (void*) &l, length, 0);
if(rv < 0) {};
//Transmitting users
for(i=0; i<last; i++) {
if(reg[i].status == 'c') {
length = strlen(reg[i].username);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) reg[i].username, length, 0);
if(rv < 0) {};
};
};
};
};
void srv_deregister(int sckt, struct users* reg, char* name, int* last) {
int i, rv, length, l;
char text[DIM];
strcpy(text, "Deregistrazione completata.\n"); //De-registration completed
for(i=0; i<*last; i++) {
if(strcmp(reg[i].username, name) == 0) { //user found
reg[i] = reg[*last];
(*last)--;
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
return;
};
};
}
int srv_register(int sckt, struct users* reg, char* name, struct sockaddr_in client, int p, int* last) { //char*
int i, rv, length, l, j, pos;
//char pos[MSG_DIM]; // = "";
char text[DIM];
char buffer[MSG_DIM];
memset(text, 0, DIM);
strcpy(text, "Registrazione effettuata con successo.\n"); //Registration completed
for(i=0; i<*last; i++) {
if(strcmp(reg[i].username, name) == 0) { //User already registered: re-connection
strcpy(text, "L'utente era gia' registrato al servizio: riconnessione completata.\n"); //Re-connection completed
reg[i].status = 'c';
reg[i].address.sin_family = client.sin_family;
reg[i].address.sin_port = p;
reg[i].address.sin_addr.s_addr = client.sin_addr.s_addr;
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
if(reg[i].msg > 0) { //messaggi offline
strcpy(text, "Messaggi offline presenti.\n"); //Offline messages found
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
//Sending number of messages to be sent
length = sizeof(*last);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
l = htons(*last);
rv = send(sckt, (void*) &l, length, 0);
if(rv < 0) {};
for(j=0; j<reg[i].msg; j++) {
sprintf(buffer, "%s > ", reg[i].sender[j]);
strcat(buffer, reg[i].pendent[j]);
length = strlen(buffer);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) buffer, length, 0);
if(rv < 0) {};
};
//Set number of messages to send to 0
reg[i].msg = 0;
} else {
strcpy(text, "Nessun messaggio offline presente.\n"); //No offline messages
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
};
return 1;
};
};
//If the user is not already registered
if(*last == MAX_UTN) { //max number of users reached
strcpy(text, "Impossibile registrarsi al servizio: numero limite di utenti raggiunto.\n"); //Max number of users reached
pos = -1;
} else {
strcpy(reg[*last].username, name);
reg[*last].address.sin_family = client.sin_family;
reg[*last].address.sin_port = p;
reg[*last].address.sin_addr.s_addr = client.sin_addr.s_addr;
reg[*last].status = 'c';
reg[*last].msg = 0;
(*last)++;
pos = 1;
};
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {}
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {}
return pos;
}
void srv_quit(int sckt, struct users* reg, char* user, int num) {
int i, length, l, rv;
char text[DIM];
memset(text, 0, DIM);
strcpy(text, "Utente disconnesso.\n"); //_User disconnected
for(i=0; i<num; i++) {
if(strcmp(reg[i].username, user) == 0) { //user actually registered to the service
if(reg[i].status == 'c') {
reg[i].status = 'o';
};
memset(®[i].address, 0, sizeof(reg[i].address));
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
printf("%s disconnesso.\n", user); //<User> disconnected
return;
};
};
//if here, user is not registered to the service
strcpy(text, "L'utente non era registrato al servizio.\n"); //User not registered
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
}
void srv_send(int sckt, struct users* reg, int num, char* dest, char* source) {
int i, rv, length, l;
char text[DIM];
char addr[ADDR_DIM];
memset(text, 0, DIM);
for(i=0; i<num; i++) {
if(strcmp(reg[i].username, dest) == 0) { //User registered
if(reg[i].status == 'c') { //user connected: provides destination UDP address to the sender (it will directly send the message)
inet_ntop(AF_INET, ®[i].address.sin_addr.s_addr, addr, sizeof(addr));
sprintf(text, "Client attualmente connesso: %s %d \n", addr , ntohs(reg[i].address.sin_port));
break;
} else { //user disconnected: save offline message
//Getting the message
rv = recv(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
length = ntohs(l);
rv = recv(sckt, (void*) reg[i].pendent, length, 0);
if(rv < 0) {};
reg[i].pendent[reg[i].msg][length] = '\0';
strcpy(reg[i].sender[reg[i].msg], source);
reg[i].msg++;
//Sending info to te sender
strcpy(text, "Messaggio salvato per l'invio offline.\n"); //Message saved offline
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
return;
};
};
};
//Here if got into the if statement
length = strlen(text);
l = htons(length);
rv = send(sckt, (void*) &l, sizeof(l), 0);
if(rv < 0) {};
rv = send(sckt, (void*) text, length, 0);
if(rv < 0) {};
}
int main(int argc, char* argv[]) {
//shared (mapped) memory
struct users* registered = mmap(0, MAX_CONN*sizeof(struct users), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
//last index with user struct to be used
int* last = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
int sd; //socket descriptor
int conn_sd; //socket descriptor after connect()
struct sockaddr_in my_addr;
struct sockaddr_in cl_addr;
int err; //for errors
int udp_port;
char check[NAME_DIM]; //will containg the username of the client connected
socklen_t len;
int pid;
int dim_rcvd_net, dim_rcvd, dim_sent_net, dim_sent;
char buffer[DIM];
char cmd[CMD_DIM];
char name[NAME_DIM];
char port[PORT_DIM];
*last = 0;
memset(registered, 0, MAX_CONN*sizeof(struct users));
memset(check,0, NAME_DIM);
puts("Avvio del servizio...\n"); //Service starting..
if(argc != 2) {
printf("Errore: troppi argomenti. \n Utilizzare solamente un argomento."); //Please use only one argument
exit(EXIT_FAILURE);
};
//Maybe check the argument itself?
sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&my_addr, 0, sizeof(my_addr));
//Socket parameters
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(atoi(argv[1]));
my_addr.sin_addr.s_addr = INADDR_ANY;
err = bind(sd, (struct sockaddr*) &my_addr, sizeof(my_addr));
if(err < 0) {};
err = listen(sd, MAX_CONN);
if(err < 0) {};
puts("Servizio attivo.\n"); //Service activated
//Concurrent server
while(1) {
len = sizeof(my_addr);
conn_sd = accept(sd, (struct sockaddr*) &cl_addr, &len);
//error check to be done
pid = fork();
if(pid == 0) {
//Child
close(sd);
while(1) {
//Command dimension
err = recv(conn_sd, (void*) &dim_rcvd_net, sizeof(dim_rcvd), 0);
if(err < 0) {};
dim_rcvd = ntohs(dim_rcvd_net);
//Command
err = recv(conn_sd, (void*) buffer, dim_rcvd, 0);
if(err < 0) {};
buffer[dim_rcvd] = '\0';
sscanf(buffer, "%s", cmd);
if(strcmp(cmd, "!help") == 0) {
srv_help(conn_sd);
};
if(strcmp(cmd, "!register") == 0) {
if(strlen(check) > 0) { //Already connected with another username
puts("Sei già connesso con altro nome.\n"); //Already connected
} else {
sscanf(buffer, "%s %s %s", cmd, name, port);
udp_port = atoi(port);
if(srv_register(conn_sd, registered, name, cl_addr, udp_port, last) == 1) {
strcpy(check, name);
};
};
};
if(strcmp(cmd, "!deregister") == 0) {
if(strlen(check) <= 0) { //if not registered
strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione.\n"); //You have to be registered
dim_sent = strlen(buffer);
dim_sent_net = htons(dim_sent);
err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
if(err < 0) {};
err = send(conn_sd, (void*) buffer, dim_sent, 0);
if(err < 0) {};
} else {
srv_deregister(conn_sd, registered, check, last);
strcpy(check, "");
};
};
if(strcmp(cmd, "!send") == 0) {
if(strlen(check) <= 0) { //if not registered
strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione.\n"); //You have to be registered
dim_sent = strlen(buffer);
dim_sent_net = htons(dim_sent);
err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
if(err < 0) {};
err = send(conn_sd, (void*) buffer, dim_sent, 0);
if(err < 0) {};
} else {
sscanf(buffer, "%s %s", cmd, name);
srv_send(conn_sd, registered, *last, name, check);
};
};
if(strcmp(cmd, "!who") == 0) {
if(strlen(check) <= 0) { //if not registered
strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione"); //You have to be registered
dim_sent = strlen(buffer);
dim_sent_net = htons(dim_sent);
err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
if(err < 0) {};
err = send(conn_sd, (void*) buffer, dim_sent, 0);
if(err < 0) {};
} else {
srv_who(conn_sd, registered, *last);
};
};
if(strcmp(cmd, "!quit") == 0) {
srv_quit(conn_sd, registered, check, *last);
close(conn_sd);
exit(EXIT_SUCCESS);
};
};
} else {
//Parent
close(conn_sd);
};
};
close(sd);
return 0;
}
编辑2
有些东西我没有得到。我刚刚重新执行了我在这里粘贴的完全相同的程序,它似乎正确地发送了消息(现在只在线)。
这可能是一些同步问题吗?
编辑3 这是作业的文字:http://www2.ing.unipi.it/c.vallati/files/reti/Progetto2017.pdf
正如我在评论中所说,它是意大利语..
答案 0 :(得分:0)
首先,我移动了UDP套接字创建。以前,在我粘贴的代码中,它位于fork()
之前。考虑到这一点,我认为这是错误的,因为父母和孩子将共享套接字而孩子会不断地使用它,而且看起来我是对的。所以我为父(发送给其他客户端)和子(接收传输)创建一个单独的UDP。
然后我想到为什么有时代码工作,有时不工作:在我以前的执行中,当程序冻结时我用Ctrl+Z
关闭它;看着htop
的输出,我注意到它的一些执行(孩子们,确切地说)仍在运行并占用套接字。所以我继续前进并终止它们。
在添加更多错误捕获代码并纠正通信中的错误之后,每次都很顺利,但仍然如此
而且我确保在关闭时让父母kill()
成为孩子。
所以是的,所有关于“双重”传输方法的预期工作(首先是文本的维度,然后是文本本身)。
答案 1 :(得分:-1)
每个端口都可以用于udp或tcp使用 有些端口由IANA主管分配给特定用途 喜欢80 for http和21 for ftp ...(维基百科页面中的表格) 你的问题是你的reciving程序阅读的内容超过了客户发送的内容 因为通过套接字发送的字符串不包含任何终止字符'\ 0'(strlen不计算终止字符'\ 0') 所以服务器首先读取消息并且不停止读取所以它打印那些奇怪的字符 解决方案是通过在发送函数中添加一个strlen(stirng)来发送终止字符,如下所示
bytes_sent = send(client_socket, thestring, strlen(thestirng)+1, 0);