I’m working on project for uni. I need to write a simple game using UDP protocol to communicate between two players in P2P mode (it needs to be only one programme). I didn’t have a problem with writing connection where client and server are seperate but P2P gives me a trouble.
Here is my current connect function:
struct connection_info {
int sockfd;
struct addrinfo *p; // struct with info about the other players IP etc. to send communications
};
//addr and port are the startup arguments
struct connection_info connect_to(char *addr, char *port) {
struct connection_info ci;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(addr, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((ci.sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to create socket\n");
}
ci.p = p;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
rv = getaddrinfo(NULL, port, &hints, &servinfo);
for (p = servinfo; p != NULL; p = p->ai_next) {
if (bind(ci.sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(ci.sockfd);
perror("listener: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
}
freeaddrinfo(servinfo);
return ci;
}
//send and receive timestamp
time_t send_invitation(int sockfd, struct addrinfo *p) {
time_t my_time = time(NULL);
if (sendto(sockfd, &my_time, sizeof(time_t), 0, p->ai_addr, p->ai_addrlen) == -1) {
perror("sendto");
exit(1);
}
printf("Sent time: %ld\n", my_time);
return my_time;
}
time_t receive_invitation(int sockfd) {
struct sockaddr_storage their_addr;
socklen_t addr_len = sizeof(their_addr);
time_t opponent_time;
if (recvfrom(sockfd, &opponent_time, sizeof(time_t), 0, (struct sockaddr *)&their_addr, &addr_len) == -1) {
perror("recvfrom");
exit(1);
}
printf("Received opponent's time: %ld\n", opponent_time);
return opponent_time;
}
//fragment of main function
int main(int argc, char *argv[]) {
if (argc > 4) {
fprintf(stderr, "Usage: <IP> <port> <optional nickname>\n");
exit(1);
}
struct connection_info ci = connect_to_server(argv[1], argv[2]);
struct game g = start(argc, argv);
struct player me = init(argc, argv);
struct sockaddr_in *opponent_ip = (struct sockaddr_in *)ci.p->ai_addr;
char opponent_ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (struct sockaddr *)&(opponent_ip->sin_addr), opponent_ip_str, INET_ADDRSTRLEN);
printf("Game in 50, version A.\n");
printf("Starting a game with %s. Type /end/ to finish or /score/ to display the current score.\n",
opponent_ip_str);
printf("Game proposal sent.\n");
time_t my_time = send_invitation(ci.sockfd, ci.p);
time_t opponent_time = receive_invitation(ci.sockfd);
printf("my_time = %ld, opponent_time %ld\n", my_time, opponent_time);
if (my_time < opponent_time) {
me.my_turn = 1;
g.current_value = rand() % 10 + 1;
me.initiator = 1;
}
It currently works but when I’m trying to send timestamps between players to set the first turn for the player that launched game first, player1 correctly recv timestamp but player2 blocks on recvfrom and unblocks after I type some number on stdin and send it to the player2 (but then player2 doesn’t receive the timestamp but the number that I’ve sent).
So I think maybe there might be a problem with my current connection. Both players listen on the same port. I’m using sendto/recvfrom functions to communicate.
Since UDP is connectionless it is not a problem with making the connection. The issue is with your send-receive protocol that you have not shown.
I’ve edited post and provided send and recv timestamp functions and fragment of main function with calls.
Suppose A starts first, sets up connection sends, then waits on recv. Now B starts up, starts connection, sends, A receives, now B does recv but packet was sent before the connection was created so was dropped. B hangs in recv. Is that what you’re seeing?
Yes, exactly but I also tried to set sleep(10) before sending timestamp and during that time started B but it doesn’t make any difference, B still hangs in recv.
Use Wireshark to see packets with timestamps. Also check firewalls.
Show 1 more comment