How to Open a Socket in C
This article will explain several methods of how to open a socket in C.
Use listen
and accept
Functions to Open a Socket in C
listen
and accept
are part of the UNIX networking facilities, sometimes called Sockets API, which implements the core functionality to deal with inter-process communications. Note that a socket is an abstract representation of the endpoint for the communication path. There are different types of sockets e.g., Unix Domain and Internet Domain, but all of them follow similar procedures for establishing the communication between two processes.
Keep in mind that networking is just communication between two running programs. At first, the socket
function is called to create the endpoint and corresponding handle. Sockets are handled with file descriptors similar to the regular files or pipes on UNIX systems. After the socket
call, it has two scenarios depending on the kind of program you are developing. Generally, we have a client-server model in network communication, where one program (server) needs to wait for others (clients) to connect with it.
In this example, we implement a server-side program that needs to listen to the specific endpoint and accept client connections. In this scenario, the bind
function is called after socket
to bind to the specific address where the program will accept the incoming connections. After bind
, listen
and accept
functions are called to form a so-called passive socket. Note that accept
blocks the process until the different process does not establish a connection using the connect
function call.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define handle_error(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
#define SOCKET_PATH "/tmp/my.sock"
enum { LISTEN_QUEUE = 100 };
int main(int argc, char *argv[]) {
int listenfd, connfd;
socklen_t len;
struct sockaddr_un servaddr, cliaddr;
listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (listenfd == -1) handle_error("socket");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strncpy(servaddr.sun_path, SOCKET_PATH, sizeof(servaddr.sun_path) - 1);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
handle_error("bind");
if (listen(listenfd, LISTEN_QUEUE) == -1) handle_error("listen");
len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
if (connfd == -1) handle_error("accept");
unlink(SOCKET_PATH);
exit(EXIT_SUCCESS);
}
Usually, the accept
call is followed by the code that implements incoming connections handling. An external program that wants to establish a connection with this server needs to know the address and port. Assuming both of them are known to the process, it invokes the connect
function after the socket
call and hopefully gets connected to the server process. Once the connection is established, both processes can write and read from the socket descriptor as having a bidirectional channel. In real-world scenarios, multiple client processes are supposed to connect to the server simultaneously; the connection handling code should be implemented concurrently. Otherwise, the server won’t be able to service more than one client at a time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define handle_error(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
#define SOCKET_PATH "/tmp/my.sock"
enum { MAXLINE = 4096, LISTEN_QUEUE = 100 };
int main(int argc, char *argv[]) {
int listenfd, connfd;
socklen_t len;
struct sockaddr_un servaddr, cliaddr;
char buf[MAXLINE];
listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (listenfd == -1) handle_error("socket");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strncpy(servaddr.sun_path, SOCKET_PATH, sizeof(servaddr.sun_path) - 1);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
handle_error("bind");
if (listen(listenfd, LISTEN_QUEUE) == -1) handle_error("listen");
len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
if (connfd == -1) handle_error("accept");
size_t ret = read(connfd, buf, MAXLINE);
if (ret == -1) handle_error("read");
printf("read %d bytes\nmessage: %s\n", connfd, buf);
unlink(SOCKET_PATH);
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook