我使用状态机模式创建了UDP聊天应用程序,但是当需要使用inet_ntoa
打印IP地址时,终端会显示0.0.0.0
。
这是我的整个代码(我将它全部粘贴,所以你可以告诉我在哪里可以改进它。我在两周前开始学习C并且可以真的使用一些建议)
#include <stdio.h> // stdin, fgets(), scanf(), printf()
#include <stdlib.h> // exit()
#include <sys/socket.h> // SOCK_DGRAM
#include <netinet/in.h> // in_addr
#include <arpa/inet.h> // inet_ntoa(), inet_aton()
#include <unistd.h> // select()
#include <string.h> // memset(), strcpy(), strerror()
#include <errno.h> // errno
#include <ctype.h> // isspace()
#define LISTENER_PORT 48879 // our 0xBEEF port :-)
#define BUFFER_SIZE 204 // 200 bytes plus 4 bytes of header
#define STDIN 0 // keyboard input
int chat_socket; // this is the only socket used in the program
typedef struct // struct the protocol
{
unsigned char version; // 1 byte version number
unsigned char command; // 1 byte command type
unsigned char seq; // 1 byte sequence number
unsigned char ack; // 1 byte acknowledgment number
char data[BUFFER_SIZE]; // 200 bytes message limit
} Packet;
Packet rxPacket; // received packet instance
Packet txPacket; // sent packet instance
enum states // enumerate the states
{
START, // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
WAIT_RESP, // Chat request sent to remote IP. Waiting for a response from the target machine
SEND_CONN_RESP, // Chat request received from remote IP. ACCEPT or REJECT
ACCEPTED, // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
STOP
};
typedef enum states states;
states state;
struct sockaddr_in my_address;
struct sockaddr_in sender_address;
struct sockaddr_in dest_address;
ssize_t r;
socklen_t sockLen = sizeof(struct sockaddr_in);
int WAIT_CONN_REQ(char *argv[])
{
/* Bind the socket to the given port */
if (bind(chat_socket, (struct sockaddr *)&my_address, sizeof(my_address))<0)
{
printf("UDP socket bind() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
printf("Socket bound to port %d!\nWaiting for CONN_REQ!\n", LISTENER_PORT);
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 1)
{
int rsp = 0;
char q = 0;
while (q != 'A' && q != 'D')
{
printf("Connection request received from %s - [A]ccept or [D]ecline?\t", inet_ntoa(sender_address.sin_addr));
scanf(" %c", &q);
}
if (q == 'A')
{
printf("You have accepted the connection request.\n");
rsp = 3;
}
else if (q == 'D')
{
printf("You have declined the connection request.\n");
rsp = 2;
}
if (rsp != 0)
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = rsp;
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
state = ACCEPTED;
}
}
return(0);
}
void lookup(FILE *names, struct sockaddr_in myip[])
{
char ipNr[32];
char chatName[32];
while(!feof(names))
{
fscanf(names, "%[^;];%s\n", ipNr, chatName);
if (strcmp(ipNr, (const char*) myip) == 0)
{
printf("Found your IP in database\n");
printf("IP: %s\n", ipNr);
printf("Username: %s\n", chatName);
printf("---\n");
return;
}
}
}
void SEND_CONN_REQ(char *argv[])
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = 1;
printf("Dest IP is %s\n", argv[0]);
inet_aton(argv[0], &dest_address.sin_addr);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&dest_address, sizeof(dest_address));
printf("Chat request sent to %s - Waiting for a response\n", inet_ntoa(dest_address.sin_addr));
state = WAIT_RESP;
}
void initialise()
{
memset(&my_address.sin_zero, 0, sizeof(my_address.sin_zero));
memset(&dest_address.sin_zero, 0, sizeof(dest_address.sin_zero));
memset(&sender_address.sin_zero, 0, sizeof(sender_address.sin_zero));
my_address.sin_family = AF_INET;
my_address.sin_addr.s_addr = INADDR_ANY;
my_address.sin_port = htons(LISTENER_PORT);
dest_address.sin_family = AF_INET;
dest_address.sin_port = htons(LISTENER_PORT);
if ((chat_socket = socket(AF_INET, SOCK_DGRAM, 0))<0)
{
printf("UDP socket allocation error no %d: %s\n", errno, strerror(errno));
exit(1);
}
}
void DATA_XCHANGE()
{
while (1)
{
txPacket.version = 1;
txPacket.command = 0;
int len = sizeof(sender_address);
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(STDIN, &readSet);
FD_SET(chat_socket, &readSet);
if ((select(32, &readSet, NULL, NULL, NULL))>0)
{
if (FD_ISSET(STDIN, &readSet))
{
fgets(txPacket.data, BUFFER_SIZE, stdin);
if (isspace(*txPacket.data) == 0)
{
printf("You: %s", txPacket.data);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
}
}
else if (FD_ISSET(chat_socket, &readSet))
{
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, (socklen_t *)&len)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 0)
{
printf("message: %s", rxPacket.data);
}
}
}
}
}
int main(int argc, char *argv[])
{
initialise();
printf("your ip is %s", inet_ntoa(my_address.sin_addr));
char *fname = "names.db";
FILE *names = fopen(fname, "r");
lookup(names, &my_address);
state = START;
while (state != STOP)
{
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ(&argv[1]);
}
else
{
WAIT_CONN_REQ(&argv[1]);
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!\n");
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 3)
{
printf("Your connection request was accepted.\n");
state = ACCEPTED;
}
else if (rxPacket.command == 2)
{
printf("Your connection request was declined.\n");
state = STOP;
}
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!\n");
break;
case ACCEPTED:
printf("ACCEPTED state!\n");
DATA_XCHANGE();
break;
case STOP:
printf("STOPPED! (switch)\n");
break;
}
}
printf("STOPPED! main()\n");
}
printf()
函数中initialise()
下面的main()
是0.0.0.0
同样,我会非常感谢此时的任何编码建议。它有助于学习过程!
答案 0 :(得分:4)
你的程序正在按照预期完成。
0.0.0.0
是INADDR_ANY
的值 - 换句话说,绑定到所有可用的接口。
在此处设置时:
my_address.sin_addr.s_addr = INADDR_ANY;
你将它设置为0,并告诉它绑定任何它可以。