server

You might also like

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 22

// server.

c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080


#define BUFFER_SIZE 1024

int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};

// Create socket file descriptor


if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}

// Define the server address


address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to the network address and port


if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

// Listen for incoming connections


if (listen(server_fd, 3) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);

// Accept a connection from a client


if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen)) < 0) {
perror("accept");
close(server_fd);
exit(EXIT_FAILURE);
}

// Communicate with the client


while (1) {
memset(buffer, 0, BUFFER_SIZE);
int valread = read(new_socket, buffer, BUFFER_SIZE);
if (valread > 0) {
printf("Client: %s\n", buffer);
send(new_socket, buffer, strlen(buffer), 0);
}
}

close(new_socket);
close(server_fd);
return 0;
}
===================================================================================
=======================
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080


#define BUFFER_SIZE 1024

int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE] = {0};
char *hello = "Hello from client";

// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

// Convert IPv4 and IPv6 addresses from text to binary form


if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}

// Connect to the server


if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}

// Communicate with the server


while (1) {
printf("Client: ");
fgets(buffer, BUFFER_SIZE, stdin);
send(sock, buffer, strlen(buffer), 0);
memset(buffer, 0, BUFFER_SIZE);
int valread = read(sock, buffer, BUFFER_SIZE);
if (valread > 0) {
printf("Server: %s\n", buffer);
}
}

close(sock);
return 0;
}
===================================================================================
====================
gcc server.c -o server
gcc client.c -o client

./server ./client
Server Code:

socket(): Creates a socket.


bind(): Binds the socket to an IP address and port.
listen(): Puts the server in passive mode, waiting for client connections.
accept(): Accepts a client connection.
read(): Reads data sent by the client.
send(): Sends data to the client.

Client Code:

socket(): Creates a socket.


connect(): Connects the socket to the server.
send(): Sends data to the server.
read(): Reads data sent by the server.
more advanced features such as handling multiple clients, implementing a message
protocol, and adding error handling to make it robust for embedded systems.
===================================================================================
====================

Handle multiple clients


// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>

#define PORT 8080


#define BUFFER_SIZE 1024
#define MAX_CLIENTS 30

int main() {
int server_fd, new_socket, client_socket[MAX_CLIENTS], max_sd, sd, activity,
valread;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE];
fd_set readfds;

// Initialize all client_socket[] to 0 so not checked


for (int i = 0; i < MAX_CLIENTS; i++) {
client_socket[i] = 0;
}

// Create socket file descriptor


if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}

// Define the server address


address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to the network address and port


if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

// Listen for incoming connections


if (listen(server_fd, 3) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);

while (1) {
// Clear the socket set
FD_ZERO(&readfds);

// Add master socket to set


FD_SET(server_fd, &readfds);
max_sd = server_fd;

// Add child sockets to set


for (int i = 0; i < MAX_CLIENTS; i++) {
sd = client_socket[i];

// If valid socket descriptor then add to read list


if (sd > 0)
FD_SET(sd, &readfds);

// Highest file descriptor number, need it for the select function


if (sd > max_sd)
max_sd = sd;
}

// Wait for an activity on one of the sockets


activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);

if ((activity < 0) && (errno != EINTR)) {


printf("select error");
}

// If something happened on the master socket, then its an incoming


connection
if (FD_ISSET(server_fd, &readfds)) {
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}

// Inform user of socket number - used in send and receive commands


printf("New connection, socket fd is %d, ip is : %s, port : %d\n",
new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

// Add new socket to array of sockets


for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_socket[i] == 0) {
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n", i);

break;
}
}
}

// Else its some IO operation on some other socket


for (int i = 0; i < MAX_CLIENTS; i++) {
sd = client_socket[i];

if (FD_ISSET(sd, &readfds)) {
// Check if it was for closing, and also read the incoming message
if ((valread = read(sd, buffer, BUFFER_SIZE)) == 0) {
// Somebody disconnected, get his details and print
getpeername(sd, (struct sockaddr *)&address, (socklen_t
*)&addrlen);
printf("Host disconnected, ip %s, port %d \n",
inet_ntoa(address.sin_addr), ntohs(address.sin_port));

// Close the socket and mark as 0 in list for reuse


close(sd);
client_socket[i] = 0;
} else {
// Set the string terminating NULL byte on the end of the data
read
buffer[valread] = '\0';
printf("Client %d: %s\n", i, buffer);
send(sd, buffer, strlen(buffer), 0);
}
}
}
}

close(server_fd);
return 0;
}
===================================================================================
====================
Initialization:

The server sets up a socket and binds it to a port, just like in the previous
example.

Client Handling:

An array client_socket keeps track of multiple clients.


The select function monitors multiple file descriptors, including the server
socket and all client sockets.
Accepting Connections:

When the server socket becomes readable, it means a new client is trying to
connect.
The server accepts the connection and adds the new client socket to the array.

Communication:

When a client socket becomes readable, the server reads the message.
If a client disconnects, the server closes the socket and removes it from the
array.
If a message is received, the server echoes it back to the client.

===================================================================================
======================
Now, the server can handle multiple clients concurrently, reading and writing to
each as needed.
This basic example demonstrates how to extend the server to handle multiple clients
in a single-threaded
manner using the select function. For more advanced handling, such as using
threads or asynchronous I/O,
further modifications would be needed.

To handle multiple clients more efficiently, we can use asynchronous I/O (non-
blocking I/O) with the `epoll` API, which is more scalable than `select` for a
large number of file descriptors. This approach is well-suited for high-performance
network servers.

Here’s an example of how to implement a server using `epoll` for asynchronous I/O
in C:

### Server Code with `epoll`

```c
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>

#define PORT 8080


#define BUFFER_SIZE 1024
#define MAX_EVENTS 10

// Function to make a file descriptor non-blocking


int set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl");
return -1;
}
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE];
int epoll_fd, nfds;
struct epoll_event ev, events[MAX_EVENTS];

// Create socket file descriptor


if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}

// Set server socket to non-blocking


set_nonblocking(server_fd);

// Define the server address


address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to the network address and port


if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

// Listen for incoming connections


if (listen(server_fd, SOMAXCONN) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);

// Create an epoll instance


if ((epoll_fd = epoll_create1(0)) == -1) {
perror("epoll_create1");
close(server_fd);
exit(EXIT_FAILURE);
}

// Add server socket to epoll


ev.events = EPOLLIN;
ev.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
perror("epoll_ctl: server_fd");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}

while (1) {
// Wait for events
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}

// Handle events
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == server_fd) {
// Handle new connections
while ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) != -1) {
set_nonblocking(new_socket);
ev.events = EPOLLIN | EPOLLET; // Edge-triggered mode
ev.data.fd = new_socket;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &ev) == -1)
{
perror("epoll_ctl: new_socket");
close(new_socket);
}
printf("New connection, socket fd is %d, ip is : %s, port : %d\
n",
new_socket, inet_ntoa(address.sin_addr),
ntohs(address.sin_port));
}
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("accept");
}
} else {
// Handle data from clients
int client_fd = events[n].data.fd;
int bytes_read;
while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) {
buffer[bytes_read] = '\0';
printf("Client %d: %s\n", client_fd, buffer);
send(client_fd, buffer, bytes_read, 0);
}
if (bytes_read == 0) {
// Connection closed by client
printf("Client %d disconnected\n", client_fd);
close(client_fd);
} else if (bytes_read == -1 && errno != EAGAIN) {
perror("read");
close(client_fd);
}
}
}
}

close(server_fd);
close(epoll_fd);
return 0;
}
```

### Explanation

1. **Non-Blocking Sockets**:
- `set_nonblocking()` sets a file descriptor to non-blocking mode using `fcntl`.
2. **Epoll Setup**:
- `epoll_create1()` creates an epoll instance.
- `epoll_ctl()` adds the server socket to the epoll instance to monitor for
incoming connections.

3. **Event Loop**:
- `epoll_wait()` waits for events on the monitored file descriptors.
- When the server socket is readable, it means a new client connection is
incoming.
- For each new connection, the client socket is set to non-blocking mode and
added to the epoll instance.
- When a client socket is readable, the server reads the message, echoes it
back, or handles disconnection.

4. **Edge-Triggered Mode**:
- `EPOLLET` sets the socket to edge-triggered mode, meaning epoll will only
notify when the file descriptor transitions from not ready to ready.

### Compile and Run

Compile the server and client code using `gcc`.

```sh
gcc server.c -o server
gcc client.c -o client
```

First, run the server:

```sh
./server
```

Then, in separate terminals, run multiple clients:

```sh
./client
```

This implementation allows the server to handle multiple clients asynchronously


using the `epoll` API, which is efficient and scalable for high-performance
applications.

===================================================================================
============================================================

Implement a message protocol in above maybe tsn

Implementing a message protocol like a simplified version of the Time-Sensitive


Networking (TSN) can help structure
communication between the server and clients. We'll create a basic protocol with
the following features:

1. **Message Length**: The first part of each message will indicate its length.
2. **Message Type**: We will define different message types for different kinds of
communication (e.g., chat messages, commands).
3. **Timestamp**: Each message will include a timestamp.
Here's how you can extend the previous example to include this protocol.

### Server Code with TSN Protocol

```c
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>

#define PORT 8080


#define BUFFER_SIZE 1024
#define MAX_EVENTS 10

// Function to make a file descriptor non-blocking


int set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl");
return -1;
}
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

// Function to get the current timestamp


char* get_timestamp() {
time_t now = time(NULL);
struct tm *t = localtime(&now);
static char timestamp[20];
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d %H:%M:%S", t);
return timestamp;
}

// Function to send a message with the protocol


void send_message(int sockfd, const char *message, const char *type) {
char buffer[BUFFER_SIZE];
int message_len = strlen(message);
char *timestamp = get_timestamp();

// Format: <message_length>:<message_type>:<timestamp>:<message>
int len = snprintf(buffer, BUFFER_SIZE, "%d:%s:%s:%s", message_len, type,
timestamp, message);
send(sockfd, buffer, len, 0);
}

// Function to parse and handle a received message


void handle_message(int client_fd, const char *buffer) {
int message_len;
char message_type[20];
char timestamp[20];
char message[BUFFER_SIZE];

// Parse the message using sscanf


sscanf(buffer, "%d:%19[^:]:%19[^:]:%1023[^\n]", &message_len, message_type,
timestamp, message);

printf("Received message from client %d:\n", client_fd);


printf(" Type: %s\n", message_type);
printf(" Timestamp: %s\n", timestamp);
printf(" Message: %s\n", message);
}

int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE];
int epoll_fd, nfds;
struct epoll_event ev, events[MAX_EVENTS];

// Create socket file descriptor


if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}

// Set server socket to non-blocking


set_nonblocking(server_fd);

// Define the server address


address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to the network address and port


if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

// Listen for incoming connections


if (listen(server_fd, SOMAXCONN) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);

// Create an epoll instance


if ((epoll_fd = epoll_create1(0)) == -1) {
perror("epoll_create1");
close(server_fd);
exit(EXIT_FAILURE);
}

// Add server socket to epoll


ev.events = EPOLLIN;
ev.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
perror("epoll_ctl: server_fd");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}

while (1) {
// Wait for events
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}

// Handle events
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == server_fd) {
// Handle new connections
while ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) != -1) {
set_nonblocking(new_socket);
ev.events = EPOLLIN | EPOLLET; // Edge-triggered mode
ev.data.fd = new_socket;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &ev) == -1)
{
perror("epoll_ctl: new_socket");
close(new_socket);
}
printf("New connection, socket fd is %d, ip is : %s, port : %d\
n",
new_socket, inet_ntoa(address.sin_addr),
ntohs(address.sin_port));
}
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("accept");
}
} else {
// Handle data from clients
int client_fd = events[n].data.fd;
int bytes_read;
while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) {
buffer[bytes_read] = '\0';
handle_message(client_fd, buffer);
send_message(client_fd, buffer, "RESPONSE");
}
if (bytes_read == 0) {
// Connection closed by client
printf("Client %d disconnected\n", client_fd);
close(client_fd);
} else if (bytes_read == -1 && errno != EAGAIN) {
perror("read");
close(client_fd);
}
}
}
}

close(server_fd);
close(epoll_fd);
return 0;
}
```

### Client Code with TSN Protocol

The client code also needs to be updated to follow the protocol.

```c
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <time.h>

#define PORT 8080


#define BUFFER_SIZE 1024

// Function to get the current timestamp


char* get_timestamp() {
time_t now = time(NULL);
struct tm *t = localtime(&now);
static char timestamp[20];
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d %H:%M:%S", t);
return timestamp;
}

// Function to send a message with the protocol


void send_message(int sockfd, const char *message, const char *type) {
char buffer[BUFFER_SIZE];
int message_len = strlen(message);
char *timestamp = get_timestamp();

// Format: <message_length>:<message_type>:<timestamp>:<message>
int len = snprintf(buffer, BUFFER_SIZE, "%d:%s:%s:%s", message_len, type,
timestamp, message);
send(sockfd, buffer, len, 0);
}

// Function to parse and handle a received message


void handle_message(const char *buffer) {
int message_len;
char message_type[20];
char timestamp[20];
char message[BUFFER_SIZE];

// Parse the message using sscanf


sscanf(buffer, "%d:%19[^:]:%19[^:]:%1023[^\n]", &message_len, message_type,
timestamp, message);

printf("Received message:\n");
printf(" Type: %s\n", message_type);
printf(" Timestamp: %s\n", timestamp);
printf(" Message: %s\n", message);
}
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE];

// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

// Convert IPv4 and IPv6 addresses from text to binary form


if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}

// Connect to the server


if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}

// Communicate with the server


while (1) {
printf("Client: ");
fgets(buffer, BUFFER_SIZE, stdin);
send_message(sock, buffer, "MESSAGE");

memset(buffer, 0, BUFFER_SIZE);
int valread

= read(sock, buffer, BUFFER_SIZE);


if (valread > 0) {
handle_message(buffer);
}
}

close(sock);
return 0;
}
```

### Explanation

1. **Message Protocol**:
- Each message sent or received follows the format
`<message_length>:<message_type>:<timestamp>:<message>`.

2. **Non-Blocking Sockets**:
- Both server and client sockets are set to non-blocking mode to handle
asynchronous I/O efficiently.

3. **Timestamp Function**:
- A helper function generates a timestamp for each message.
4. **Send and Handle Messages**:
- `send_message()` formats and sends messages following the protocol.
- `handle_message()` parses and displays received messages.

5. **Edge-Triggered Epoll**:
- The server uses `epoll` in edge-triggered mode (`EPOLLET`) to handle high-
performance I/O.

### Compile and Run

Compile the server and client code using `gcc`.

```sh
gcc server.c -o server
gcc client.c -o client
```

First, run the server:

```sh
./server
```

Then, in separate terminals, run multiple clients:

```sh
./client
```

This implementation introduces a basic protocol with message length, type, and
timestamp, enhancing communication structure
and readability for both the server and clients. The use of `epoll` ensures
efficient handling of multiple clients asynchronously.

===================================================================================
==================================================

When it comes to embedded systems, particularly for switches and other networking
hardware, there are several protocols that could be suitable depending on the
specific requirements of the system. Here are a few options, along with a brief
overview and example implementations:

### 1. MQTT (Message Queuing Telemetry Transport)

MQTT is a lightweight messaging protocol designed for small sensors and mobile
devices. It's suitable for embedded systems due to its low bandwidth usage and
support for reliable communication.

#### Example Implementation:

**Server (Broker)**:
```c
// Example using an MQTT library such as Eclipse Paho

#include "MQTTClient.h"

#define ADDRESS "tcp://localhost:1883"


#define CLIENTID "ExampleClientPub"
#define TOPIC "example/topic"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L

int main(int argc, char* argv[]) {


MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
int rc;

MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE,


NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;

if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {


printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}

MQTTClient_message pubmsg = MQTTClient_message_initializer;


pubmsg.payload = PAYLOAD;
pubmsg.payloadlen = strlen(PAYLOAD);
pubmsg.qos = QOS;
pubmsg.retained = 0;
MQTTClient_deliveryToken token;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
printf("Message with delivery token %d delivered\n", token);

MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
```

**Client**:
```c
#include "MQTTClient.h"

#define ADDRESS "tcp://localhost:1883"


#define CLIENTID "ExampleClientSub"
#define TOPIC "example/topic"
#define QOS 1

void delivered(void *context, MQTTClient_deliveryToken dt) {


printf("Message with token value %d delivery confirmed\n", dt);
}

int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message


*message) {
printf("Message arrived\n");
printf("topic: %s\n", topicName);
printf("message: %.*s\n", message->payloadlen, (char*)message->payload);
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
void connlost(void *context, char *cause) {
printf("Connection lost\n");
printf("cause: %s\n", cause);
}

int main(int argc, char* argv[]) {


MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
int rc;

MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE,


NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {


printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}

printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"


"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
MQTTClient_subscribe(client, TOPIC, QOS);

int ch;
do {
ch = getchar();
} while(ch!='Q' && ch != 'q');

MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
```

### 2. CoAP (Constrained Application Protocol)

CoAP is a specialized web transfer protocol for use with constrained nodes and
networks in the Internet of Things (IoT). It's suitable for embedded systems due to
its simplicity and efficiency.

#### Example Implementation:

**Server**:
```c
// Example using libcoap (CoAP library)

#include <coap2/coap.h>

static void handle_get_request(coap_context_t *ctx, struct coap_resource_t


*resource, coap_session_t *session, coap_pdu_t *request, coap_binary_t *token,
coap_string_t *query, coap_pdu_t *response) {
const char* response_data = "Hello CoAP!";
coap_add_data(response, strlen(response_data), (unsigned char *)response_data);
}

int main() {
coap_context_t* coap_context;
coap_address_t listen_address;
coap_resource_t* resource;

coap_startup();
coap_context = coap_new_context(NULL);
if (!coap_context) {
return EXIT_FAILURE;
}

coap_address_init(&listen_address);
listen_address.addr.sin.sin_family = AF_INET;
listen_address.addr.sin.sin_addr.s_addr = INADDR_ANY;
listen_address.addr.sin.sin_port = htons(5683);

if (!coap_new_endpoint(coap_context, &listen_address, COAP_PROTO_UDP)) {


coap_free_context(coap_context);
return EXIT_FAILURE;
}

resource = coap_resource_init(coap_make_str_const("example"), 0);


coap_register_handler(resource, COAP_REQUEST_GET, handle_get_request);
coap_add_resource(coap_context, resource);

while (1) {
coap_io_process(coap_context, COAP_IO_WAIT);
}

coap_free_context(coap_context);
coap_cleanup();
return 0;
}
```

**Client**:
```c
// Example using libcoap (CoAP library)

#include <coap2/coap.h>

static void response_handler(coap_context_t *ctx, coap_session_t *session,


coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) {
unsigned char* data;
size_t data_len;
coap_get_data(received, &data_len, &data);
printf("Received: %.*s\n", (int)data_len, data);
}

int main() {
coap_context_t* coap_context;
coap_address_t dst;
coap_session_t* session;
coap_pdu_t* request;
static const coap_uri_t uri = { COAP_URI_SCHEME_COAP, COAP_DEFAULT_PORT, 0,
(const uint8_t*)"example", 7 };

coap_startup();
coap_context = coap_new_context(NULL);
if (!coap_context) {
return EXIT_FAILURE;
}

coap_address_init(&dst);
dst.addr.sin.sin_family = AF_INET;
dst.addr.sin.sin_port = htons(5683);
inet_pton(AF_INET, "127.0.0.1", &dst.addr.sin.sin_addr);

session = coap_new_client_session(coap_context, NULL, &dst, COAP_PROTO_UDP);


if (!session) {
coap_free_context(coap_context);
return EXIT_FAILURE;
}

request = coap_new_pdu(session);
request->type = COAP_MESSAGE_CON;
request->tid = coap_new_message_id(session);
request->code = COAP_REQUEST_GET;
coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
coap_register_response_handler(coap_context, response_handler);
coap_send(session, request);

coap_io_process(coap_context, COAP_IO_WAIT);
coap_session_release(session);
coap_free_context(coap_context);
coap_cleanup();
return 0;
}
```

### 3. Protobuf (Protocol Buffers) over TCP/UDP

Google's Protocol Buffers (Protobuf) is a language-neutral, platform-neutral,


extensible mechanism for serializing structured data. It's suitable for embedded
systems due to its compact binary format and efficiency.

#### Example Implementation:

This example assumes you have installed the `protobuf-c` library and the Protocol
Buffers compiler.

**Message Definition (`message.proto`)**:


```proto
syntax = "proto3";

message ExampleMessage {
string type = 1;
string timestamp = 2;
string message = 3;
}
```

Compile the `message.proto` file using `protoc`:


```sh
protoc --c_out=. message.proto
```

**Server**:
```c
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "message.pb-c.h"

#define PORT 8080


#define BUFFER_SIZE 1024

int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
uint8_t buffer[BUFFER_SIZE];

// Create socket file descriptor


if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}

// Define the server address


address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to the network address and port


if (bind(server_fd, (struct sockaddr *)&

address, sizeof(address)) < 0) {


perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

// Listen for incoming connections


if (listen(server_fd, 3) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);

if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t


*)&addrlen)) < 0) {
perror("accept");
close(server_fd);
exit(EXIT_FAILURE);
}

int valread = read(new_socket, buffer, BUFFER_SIZE);


ExampleMessage *message = example_message__unpack(NULL, valread, buffer);

if (message == NULL) {
fprintf(stderr, "error unpacking incoming message\n");
close(new_socket);
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Received message: type=%s, timestamp=%s, message=%s\n",


message->type, message->timestamp, message->message);

example_message__free_unpacked(message, NULL);
close(new_socket);
close(server_fd);
return 0;
}
```

**Client**:
```c
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "message.pb-c.h"

#define PORT 8080


#define BUFFER_SIZE 1024

// Function to get the current timestamp


char* get_timestamp() {
time_t now = time(NULL);
struct tm *t = localtime(&now);
static char timestamp[20];
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d %H:%M:%S", t);
return timestamp;
}

int main() {
int sock = 0;
struct sockaddr_in serv_addr;
uint8_t buffer[BUFFER_SIZE];

// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

// Convert IPv4 and IPv6 addresses from text to binary form


if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}

// Connect to the server


if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}

ExampleMessage message = EXAMPLE_MESSAGE__INIT;


message.type = "MESSAGE";
message.timestamp = get_timestamp();
message.message = "Hello Protobuf!";

size_t message_len = example_message__get_packed_size(&message);


example_message__pack(&message, buffer);

send(sock, buffer, message_len, 0);


close(sock);
return 0;
}
```

### Summary

- **MQTT**: Lightweight and suitable for constrained devices, providing a


publish/subscribe model.
- **CoAP**: Ideal for constrained nodes and networks, using a request/response
model similar to HTTP.
- **Protobuf over TCP/UDP**: Efficient binary serialization, suitable for
structured data communication in embedded systems.

Each protocol has its strengths and can be chosen based on specific requirements
such as latency, bandwidth, and complexity of the embedded system.

===================================================================================
=====================================================

You might also like