Wykonując prostą aplikację do czatu z użyciem C-sockets
Wprowadzenie to Socket Programming in C
Building a chat application from scratch is one of thee best ways to master network programming fundamentals. Using C sockets gives you direct control over every network interaction, from connection establiment to o data transfer. Thi project walks thigh creating a multi- client chat server and a client program that communicate in real time, send and necesvage, you will learn how to cuté sockets, bind them to ports, listen for connections, active clients clients, send and nesságles, and handle handle multiple userves users. The useillles. The yohers yohern condire nerepláte nen nereplies.
We assume basic knowdge of C programming (variables, loops, functions, pointers) and a working environment with a C compiler (GCC) and POSIX- compatible ble operating system (Linux, macOS, or WSL on Windows). All code examples follow the BSD socket API, which is the standard for network programming in Unix- like systems.
Sockets understanding C
A socket is an endpoint for communication between two machines over a network. In the POSIX socket API, a socket is contributed by an integer file descriptor. The most contribun type ar equil 1; description 1; FLT: 0 equire3; description 3; stream sockets establishment 1; FLT: 1 established, wet: (SOCK _ STREAM) using TCP and Espal; degr. UDIP. For. FLT: 2 establing; dagram sockets estatiotchant, wet.
Te cre functions that make up thee socket API ar e:
- - Stworzenia new socket and returns a file descriptol.
- Xiv1; Xiv1; FLT: 1 Xiv3; Xiv3; - Associates a socket with a specific IP addios andd port number.
- Xiv1; Xiv1; FLT: 2 Xiv3; Xiv3; - Marks a socket as passive, ready tu accordt incoming connections.
- - Blocks until a client connects, then returns a new socket for that specific client.
- Xi1; Xi1; FLT: 4 Xi3; Xi3; - Used by a client to initiate a connection to a server.
- Xi1; Xi1; FLT: 5 Xi3; Xi3; and Xi1; Xi1; FLT: 6 Xi3; Xi3; - Transmit and receive data over a connectod socket.
All these functions are demande in eng1; Xi1; FLT: 7; Xi3; Xi3;. Additional headers like 1; Xi1; FLT: 8 Xi3; Xi3; (for Xi1; FLT: 9 XI3; FLT: 9 XI3; FLT: 1; FLT: 10 XI3; FLT: 10 XI3; FLT: Xi3; (for IP accordions conversion) are also nets; Understanding these headers and thee structures they definie is essential. Thee 1; FLT: 1; FLT: 111VED 3D; structure holds thes accorrity, port (in work bye order; 1s), ander; 1s; FLV; 1s; FLV; FLV; FLV; F@@
For a deeper reference, consult present 1; Present 1; FLT: 0 Presentation 3; Presentation 3; Beej 's Guide to o Network Programming presentation 1; Presentation 1; FLT: 1 Presentation 3; Reference That explains every function witch clear examples.
Setting Up the Servir
Te server is thee central hub of thee chat application. It listens for client connections, receives messages from any client, and Broaddcasts those messages to all teir connected clients. Building a robutt server requires careful handling of each system call andd potential errors.
Creating thee Socket
Te first step is to create a socket wigh the behind 1; Xi1; FLT: 14 behind 3; Xi3; functionol:
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket failed");
exit(EXIT_FAILURE);
}
- Xi1; Xi1; FLT: 0 Xi3; Xi3; AF _ INET Xi1; Xi1; FLT: 1 Xi3; Xi3; - Adresy family for IPv4.
- (Dz.U. L 311 z 15.11.2014, s. 1).
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Xi1; FLT: 1 Xi3; Xi3; - Protocol; defaults to TCP when SOCK _ STREAM is used.
Zawsze sprawdza, czy te return value; a socket creation failure mutt be handled gracefuly. The employ1; Betting 1; FLT: 16 bething 3; Bettle3; functionn prints the error description to stderr.
Binding thee Socket
Next, we bind thee socket to a local adresss andd port. Clients will connect to tis adresss.
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // Bind to all local interfaces
server_addr.sin_port = htons(8080); // Port number
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
(1); Xi1; FLT: 0 is 3; Xi3; INADDR _ ANY Signed 1; Xi1; FLT: 1 is 3; Xi1; FLT: 1 is 3; 5x01 accorts connections on any IP addits assigned to thee host. The port number (8080 in this example) is chosen tte to avoid well-known services; values abova 1024 are typical for user-level programs. Notie that Britig1; FLT: 18 contable 3; ensures the port ins network bye order (bir-endian).
Listening for Connections
After binding, the server mutt listen for incoming connections. The message 1; dem1; FLT: 19 messages 3; demand3; call places the socket into a passive mode where it will queue e incoming connection requests.
if (listen(server_fd, 5) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}
Te sekundowe argumenty (5) i te backlog - thee maximum ums length of thee queue of pending connections. A hiper value may bee used for busy servers, but thee system imposes an upper limit (often present 1; eng.1; FLT: 21 presents 3; eng3;).
Akcepting Client Connections
To accordt a client, we call indic1; Xi1; FLT: 22 contribution 3; Xion3; in a loop. It returns a new socket file descripptor for that specific client, while thee original server socket continues listening.
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
perror("accept");
// In a real server, handle the error without exiting
continue;
}
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
printf("New connection from %s:%d\n", client_ip, ntohs(client_addr.sin_port));
For each accordted client, we obtain the client 's IP and port. Thi information is useful for logging and potential accords control. The client socket is then ready for data transfer.
Handling Data from a Client
Once a client is connected, the server must be able to read messages andd broadcast them. For a simple server that handles one e client at a time, the typical pattern is to call indi1; indi1; FLT: 24 condition 3; indi3; on the client socket. However, to truly support multiple clients, you need concurrency.
Programing thee Client
Thee client is simpler: it creates a socket, connects to thee server, and then enters a loop when e reads user input and sends it to thee server, while anevanously receiving broadcast messages frem thee server.
Creating andd Connecting
First, the client socket is created exactly as the server did. Then it connects using the server 's IP accords andd port:
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// Convert IP address from text to binary
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("invalid address / address not supported");
close(sock);
exit(EXIT_FAILURE);
}
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
close(sock);
exit(EXIT_FAILURE);
}
Here Reg. 1; Here 1; Xion1; FLT: 26 Xion3; Xion3; converts the human-readable IP adresses string to binary formm. For production code, you might resolve hostnames with 1; Xion1; FLT: 27 Xion3; Xion3; Xion3;.
Wymień pętlę
After connecting, the client needs to send messages type by the user andreceive messages frem the server conneanousy. A consun approach is to use two threads: one for reading frem stdin and sending, anotherr for recediving from the socket. Alternatively, you can use non-blocking I / O or thee mee 1; independirewing ezy, but for a for a read 3d; system call. A minimal client that only sends messages (and ibereedirediredivingiving) is, but for a for a for chat a need bidictional dictional communication.
Te za-plyng szkieletowe wykorzystuje 1; Xion1; FLT: 29 contribution 3; Xion3; tlo create a child process that handles incoming messages while thee parent handles outgoing. For threading, prefer dos1; Xion1; FLT: 30 contribution 3; Xion3; for portability.
// Fork to handle send and receive separately
if (fork() == 0) {
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int n = recv(sock, buffer, sizeof(buffer) - 1, 0);
if (n <= 0) {
printf("Server disconnected\n");
break;
}
printf("%s", buffer);
}
close(sock);
exit(0);
} else {
char message[1024];
while (fgets(message, sizeof(message), stdin) != NULL) {
send(sock, message, strlen(message), 0);
memset(message, 0, sizeof(message));
}
close(sock);
}
This Pattern works, but in a real application you would need to handle message framing conpertily, as TCP is a stream protocol - messages may be split or concatenatenad. A simply solution is to use a delimiter such as presens 1; Il; FLT: 32 contribul 3; Il; Il send thee length of thee message firste.
Handling Multiple Clients
Te server must manage many clients at once. Two populaar methods are present 1; direction 1; FLT: 0 gire3; direc3; multi-threading direc1; direc1; FLT: 1 gire3; direc3; (one thread per client) and direc1; direc1; FLT: 2 direc3; FLT: 3; I / O multiplexing direc1; direc1; FLT: 3; (using direc1; direc1; FLT: 33X3; oR X3; OR 1; direc1; FLT: 34 direcreac3; 3;). Each has tradefs-offs.
Using Threads (pthread)
Nie jest to threated model, że main loop akceptuje client and creats a new thread dedicate to to that client. The thread handles receiving messages and Broadcasting them. Thi s is conceptually simplite andd works well for dozens of clients, but thread overhead can accore aid issie with timetronas of connections.
void *handle_client(void *arg) {
int client_fd = *(int*)arg;
free(arg); // Free the heap‑allocated int
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int n = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
if (n <= 0) {
// Client disconnected
break;
}
// Broadcast to all other clients
// (requires a mutex‑protected list of client fds)
}
close(client_fd);
return NULL;
}
while (1) {
int *pclient = malloc(sizeof(int));
*pclient = accept(server_fd, ...);
pthread_t tid;
pthread_create(&tid, NULL, handle_client, pclient);
pthread_detach(tid); // Automatically clean up on exit
}
Remember to protect shared data (like the lict of connected sockets) with a mutex. Also, be careful with thread-safety of index1; index1; FLT: 36 context 3; index3; - it 's generally safe, but you mutt avoid concurrent writes to the same socket.
Using select ()
The thread to monitor multiple file descriptory for reability, writability, or errors. This avoids thee overhead of man threads and is efficient for a moderate number of connections. The server maintains a set of file descriptors (server socket + all client sockets). When measun 1; FLT: 38 connect3; verts 3returs, we iterate the set tte tfind which ptor ires).
fd_set readfds;
int max_fd = server_fd;
while (1) {
FD_ZERO(&readfds);
FD_SET(server_fd, &readfds);
for (int i = 0; i < client_count; i++) {
FD_SET(clients[i], &readfds);
if (clients[i] > max_fd) max_fd = clients[i];
}
int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);
if (activity < 0) { perror("select"); break; }
if (FD_ISSET(server_fd, &readfds)) {
// Accept new client
int new_socket = accept(server_fd, ...);
clients[client_count++] = new_socket;
}
for (int i = 0; i < client_count; i++) {
int sd = clients[i];
if (FD_ISSET(sd, &readfds)) {
char buffer[1024];
int n = recv(sd, buffer, sizeof(buffer), 0);
if (n <= 0) {
// Remove client
close(sd);
clients[i] = clients[--client_count];
i--;
} else {
// Broadcast buffer to all other clients
}
}
}
}
One faciliage of indi1; Xi1; FLT: 40 Superior 3; Xi3; is portability, but is is limited byy indic1; Xi1; FLT: 41 XI3; XI3; (usually 1024). For higher scalality, use portability, use 1; FLT: 42 XI3; FLT: 3; or XI1; FLT: 43 XI3; FL3; (Linux-specific). XI1; FLT: 0 XI3; XI3; THE select (2) man page XIX1; XIXIXIX1; FLT: 1 X3XIX3; XIX3Sup3Supés.
Wdrożenie Protocol Simple Chat
To make he chat consurent, you need a minimal protocol. Without a protocol, messages from different clients can interleafe on thee wire. At a minimum, decide on a message format. A simple approach: each message is a single line ending with vors 1; FLT: 44 memorial 3; British; The server prepends the sender 's name or ID before widcasting. For example:
[Alice] Hello everyone!
[Bob] Hi Alice!
When a client sends a message, the server reads the line (using a delimiter) and then sends it to all teir clients, optionally with a prefix. Message framing is critical. A robutt methood is to send a fixed-size header that included thee message length, followed by the payload. This prevents issues with partial reads.
struct chat_message {
uint32_t length; // in network byte order
char data[1024]; // up to 1024 bytes
};
That server reads exactly 4 bytes to get thee length, then reads that many bytes for thee data. This contributes messages are received in one e piece.
Error Handling and Beszt Practices
Network programming is full of edge case. A few essential practices:
- Always check the return value of previo1; Xi1; FLT: 47 XI3; XI3;, XI1; FLT: 48 XI3; XI3;, XI1; FLT: 49 XI3; XI3; FLT: 50 XI3; XI3; FLT: XI1; XI1; FLT: 51 XI3; FLT: 51 XI3; XI1; FLT: 52 XI3; XI1; FLT: 53 XI3; X3;, And close sockets on failure.
- Use Instant 1; EDB 1; FLT: 54 DCA 3; EDB; OR DCA; EDF: 55 DCA; EDF 3; EDF 3; EDC 3; TO log DCA; DCA.
- Set the socket option preci1; Precision 1; FLT: 56 precision 3; Precidi3; on thee server socket to avoid representation; Adresats already in use precidicute quote; errors when n restarting.
- Handle signals like eng1; Xi1; FLT: 57 Xi3; Xi3; (which ch can occur when writing to a closed socket) by ignorang them or using eng1; Xi1; FLT: 58 Xiond3; Xion3;.
- Use non-blocking I / O or timeouts wigh vig1; Xi1; FLT: 59 Xion3; Xion3; to prevent the server frem hanging on a dead client.
- Zawsze jest zero out buffers before reading to ensure you don 't send restver data.
- Cleun up resources - close sockets and free allocated memory - to prevent less.
For a deeper dive into error handling and advanced techniques, read the presence 1; British 1; FLT: 0 presentation 3; British 3; 3; POSIX specification for connect () Reference 1; British 1; FLT: 1 presentation 3; British 3; And related functions.
Expanding the Application
Once you have a working multi-client chat, you can add exacures to make e it more useful:
- Xi1; Xi1; FLT: 0 Xi3; Xi3; User uwierzytelniation Xi1; Xi1; FLT: 1 Xi3; Xi3; - Klienci provide a username on connect; the server validates andd stores it.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Private messaging Xi1; Xi1; FLT: 1 Xi3; Xi3; - Allow quote; / msg username text Xiquit; Commands that the server routes only ty the target client.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Room / channel support Xi1; Xi1; FLT: 1 Xi3; Xi3; - Clients can join named rooms; messages are Broadcast only with a room.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; File transfer Xi1; Xi1; FLT: 1 Xi3; Xi3; - Send binary files by implementationg a separate data channel or by sending file metadata andd raw bytes over the same socket.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Xi1; FLT: 1 Xi3; Xi3; - Usie OpenSSL or TLS to security communication.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Graphical user interface Xi1; Xi1; FLT: 1 Xi3; Xi3; - Write a GUI client (using GTK, Qt, or even a web front-end with a backend bridge).
- - Log messages to a file or database for later retrieval.
Each expansion teaches valuable concepts: protocol design, concurrency, security, and user experience. The foundation you build now will support any of these enhancements.
Konkluzja
Stworzenie uproszczonego programu chat application using C sockets is excellent hands for anyone learning network programming. You have learned to create servers andd clients, manage multiple connections with threads or orl; 1; FLT: 60 context 3; exemplies message over TCP, and implement a basic chat protocol. Thee code examples provide a starting point that you compile, tett, tett, and modify. Ayos expresend the project, youan natorally nature tables provide a starting point tail vre vre-dit-dit.
For additional practice, consider implementing a simplete HTTP server or a peer-to-peer file sharing tool. The skills are directly transferable. And contexber - always read thee documentation. Montext 1; FLT: 0 context 3; Antex3; Thee socket (7) man page bex1; Antex1; FLT: 1 contex3; is your constant commercion.