C Server Development Tutorial64


Introduction

In this tutorial, we will guide you through the process of developing a C server using sockets. We will cover the basics of socket programming, including creating sockets, binding them to addresses, listening for incoming connections, and sending and receiving data over the network. We will also provide a simple example of a C server that can handle incoming HTTP requests.

Prerequisites

Before you begin this tutorial, you should have a basic understanding of C programming. You should also have a working C compiler installed on your system. Additionally, you may need to install some additional libraries, such as the Berkeley sockets library, depending on your operating system and development environment.

Creating a Socket

The first step in developing a C server is to create a socket. A socket is a software endpoint that allows two processes to communicate over a network. To create a socket, we use the `socket()` function. The `socket()` function takes three arguments: the address family, the socket type, and the protocol.```c
int socket(int domain, int type, int protocol);
```

The address family specifies the type of network address that will be used. The most common address families are `AF_INET` (for IPv4 addresses) and `AF_INET6` (for IPv6 addresses). The socket type specifies the type of socket that will be created. The most common socket types are `SOCK_STREAM` (for TCP sockets) and `SOCK_DGRAM` (for UDP sockets). The protocol specifies the protocol that will be used for communication. The most common protocols are `IPPROTO_TCP` (for TCP) and `IPPROTO_UDP` (for UDP).

Binding a Socket to an Address

Once a socket has been created, it must be bound to an address. This is done using the `bind()` function. The `bind()` function takes two arguments: the socket descriptor and the address structure.```c
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
```

The socket descriptor is the integer that was returned by the `socket()` function. The address structure contains the address and port number to which the socket should be bound. The `addrlen` argument specifies the length of the address structure.

Listening for Incoming Connections

Once a socket has been bound to an address, it can begin listening for incoming connections. This is done using the `listen()` function. The `listen()` function takes two arguments: the socket descriptor and the maximum number of pending connections that the socket can queue.```c
int listen(int sockfd, int backlog);
```

The maximum number of pending connections is typically set to a small value, such as 5 or 10. This prevents the server from being overwhelmed with incoming connections and crashing.

Accepting Incoming Connections

When a client attempts to connect to the server, the server's `listen()` function will return a new socket descriptor. This new socket descriptor is used to communicate with the client. The `accept()` function is used to accept the incoming connection.```c
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
```

The `accept()` function takes three arguments: the socket descriptor, the address structure, and the length of the address structure. The address structure will contain the address and port number of the client that is attempting to connect.

Sending and Receiving Data

Once a connection has been established, data can be sent and received using the `send()` and `recv()` functions. The `send()` function is used to send data to the client, while the `recv()` function is used to receive data from the client.```c
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
```

The `send()` function takes four arguments: the socket descriptor, the data buffer, the length of the data buffer, and the flags. The `recv()` function takes four arguments: the socket descriptor, the data buffer, the length of the data buffer, and the flags.

Closing a Socket

When a connection is no longer needed, the socket should be closed using the `close()` function. The `close()` function takes one argument: the socket descriptor.```c
int close(int sockfd);
```

Closing a socket will release the resources that are associated with it.

Example

Here is a simple example of a C server that can handle incoming HTTP requests:```c
#include
#include
#include
#include
#include
int main() {
// Create a socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
return EXIT_FAILURE;
}
// Bind the socket to an address
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(8080);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return EXIT_FAILURE;
}
// Listen for incoming connections
if (listen(sockfd, 5) < 0) {
perror("listen");
return EXIT_FAILURE;
}
// Accept incoming connections
while (1) {
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
int newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);
if (newsockfd < 0) {
perror("accept");
continue;
}
// Handle the incoming connection
while (1) {
char buffer[256];
memset(buffer, 0, sizeof(buffer));
int n = recv(newsockfd, buffer, sizeof(buffer), 0);
if (n < 0) {
perror("recv");
break;
} else if (n == 0) {
break;
}
// Send a response back to the client
char response[] = "HTTP/1.1 200 OK\rContent-Length: 11\rContent-Type: text/plain\r\rHello world!";
int m = send(newsockfd, response, strlen(response), 0);
if (m < 0) {
perror("send");
break;
}
}
// Close the connection
close(newsockfd);
}
// Close the socket
close(sockfd);
return EXIT_SUCCESS;
}
```

2024-12-29


Previous:EDIUS 6 Editing Tutorial: Comprehensive Guide for Beginners

Next:Cloud Computing Speeds Up Innovation