udp_chat.c

Download
c 111 lines 3.1 KB
  1/**
  2 * UDP Chat (peer-to-peer)
  3 *
  4 * Simple UDP-based chat. Each instance can both send and receive.
  5 * Uses select() to monitor both stdin and the UDP socket.
  6 *
  7 * Build: make
  8 * Usage: ./udp_chat <local_port> <remote_ip> <remote_port>
  9 *   Example: Terminal 1: ./udp_chat 9001 127.0.0.1 9002
 10 *            Terminal 2: ./udp_chat 9002 127.0.0.1 9001
 11 */
 12
 13#include <stdio.h>
 14#include <stdlib.h>
 15#include <string.h>
 16#include <unistd.h>
 17#include <sys/socket.h>
 18#include <sys/select.h>
 19#include <netinet/in.h>
 20#include <arpa/inet.h>
 21
 22#define BUF_SIZE 1024
 23
 24int main(int argc, char *argv[]) {
 25    if (argc != 4) {
 26        fprintf(stderr, "Usage: %s <local_port> <remote_ip> <remote_port>\n",
 27                argv[0]);
 28        exit(EXIT_FAILURE);
 29    }
 30
 31    int local_port = atoi(argv[1]);
 32    const char *remote_ip = argv[2];
 33    int remote_port = atoi(argv[3]);
 34
 35    /* Create UDP socket */
 36    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
 37    if (sock_fd < 0) {
 38        perror("socket");
 39        exit(EXIT_FAILURE);
 40    }
 41
 42    /* Bind to local port */
 43    struct sockaddr_in local_addr = {
 44        .sin_family = AF_INET,
 45        .sin_addr.s_addr = INADDR_ANY,
 46        .sin_port = htons(local_port)
 47    };
 48
 49    if (bind(sock_fd, (struct sockaddr *)&local_addr,
 50             sizeof(local_addr)) < 0) {
 51        perror("bind");
 52        close(sock_fd);
 53        exit(EXIT_FAILURE);
 54    }
 55
 56    /* Setup remote address */
 57    struct sockaddr_in remote_addr = {
 58        .sin_family = AF_INET,
 59        .sin_port = htons(remote_port)
 60    };
 61    inet_pton(AF_INET, remote_ip, &remote_addr.sin_addr);
 62
 63    printf("UDP Chat - listening on port %d, sending to %s:%d\n",
 64           local_port, remote_ip, remote_port);
 65    printf("Type messages (Ctrl+D to quit):\n\n");
 66
 67    fd_set read_fds;
 68    char buffer[BUF_SIZE];
 69    int max_fd = (sock_fd > STDIN_FILENO) ? sock_fd : STDIN_FILENO;
 70
 71    while (1) {
 72        FD_ZERO(&read_fds);
 73        FD_SET(STDIN_FILENO, &read_fds);
 74        FD_SET(sock_fd, &read_fds);
 75
 76        int ready = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
 77        if (ready < 0) {
 78            perror("select");
 79            break;
 80        }
 81
 82        /* User typed something */
 83        if (FD_ISSET(STDIN_FILENO, &read_fds)) {
 84            if (fgets(buffer, BUF_SIZE, stdin) == NULL)
 85                break;
 86
 87            sendto(sock_fd, buffer, strlen(buffer), 0,
 88                   (struct sockaddr *)&remote_addr, sizeof(remote_addr));
 89        }
 90
 91        /* Received a message */
 92        if (FD_ISSET(sock_fd, &read_fds)) {
 93            struct sockaddr_in from_addr;
 94            socklen_t from_len = sizeof(from_addr);
 95            ssize_t bytes = recvfrom(sock_fd, buffer, BUF_SIZE - 1, 0,
 96                                     (struct sockaddr *)&from_addr,
 97                                     &from_len);
 98            if (bytes > 0) {
 99                buffer[bytes] = '\0';
100                char ip[INET_ADDRSTRLEN];
101                inet_ntop(AF_INET, &from_addr.sin_addr, ip, sizeof(ip));
102                printf("[%s:%d] %s", ip, ntohs(from_addr.sin_port), buffer);
103            }
104        }
105    }
106
107    close(sock_fd);
108    printf("Chat ended\n");
109    return 0;
110}