I am reading "The Linux Programming Interface" by Michael Kerrisk. I'm studying about sockets, and I made a simple application using sockets on the unix domain.
I want to know if I'm using sockets properly. Also what features should I add?
There are two programs: server and client. client requires an input file, and it sends the contents of the file to server. server receives the data and prints it out.
Code:
server.c
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFFER_LEN 128
void fatal(char* message) {
// Print error message and exit
perror(message);
exit(EXIT_FAILURE);
}
void socket_comm() {
const char* SOCKET_PATH = "/home/tux/temp/server_sock";
int socket_fd;
// Create socket
socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd == -1) {
fatal("Error while initializing socket");
}
// Bind socket to SOCKET_PATH
socklen_t socket_addr_size;
struct sockaddr_un socket_addr;
memset(&socket_addr, 0, sizeof(struct sockaddr_un)); // Initialize to 0
socket_addr.sun_family = AF_UNIX;
strncpy(socket_addr.sun_path, SOCKET_PATH, sizeof(socket_addr.sun_path) - 1);
socket_addr_size = sizeof(socket_addr);
if (bind(socket_fd, (struct sockaddr *) &socket_addr, sizeof(struct sockaddr_un)) == -1) {
fatal("Error while binding socket");
} else {
printf("Successfully generated server-side socket\n");
}
// Mark as passive
if (listen(socket_fd, 8) == -1) {
fatal("Cannot mark socket as passive");
}
// Connect to client and receive data
ssize_t numread;
char buffer[BUFFER_LEN + 1];
while (1) {
// Connect to client
int connect_fd = accept(socket_fd, (struct sockaddr*) &socket_addr, &socket_addr_size);
if (connect_fd == -1) {
fatal("Cannot accept connections");
sleep(1);
}
printf("Connected to client\n");
// Receive data
while ((numread = read(connect_fd, buffer, BUFFER_LEN)) > 0) {
buffer[numread] = '\0';
printf("%s", buffer);
}
}
}
int main() {
socket_comm();
return 0;
}
client.c
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
void fatal(char* message) {
// Print message and exit
perror(message);
exit(EXIT_FAILURE);
}
long get_data(int argc, char* argv[], char** buffer) {
// Command line argument must be path to file
// option "-h" or "--help" prints help
if (argc != 2 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
printf("Usage: %s filepath\n",argv[0]);
printf("Sends data to the server\n");
exit(EXIT_SUCCESS);
}
// Open file
FILE* fp;
fp = fopen(argv[1],"r");
if (fp == NULL) {
fatal("Cannot open file");
}
// Determine file size
if (fseek(fp, 0, SEEK_END) == -1) {
fatal("Error determining file size");
}
long size = ftell(fp);
if (size == -1) {
fatal("Error determining file size");
}
rewind(fp);
// Allocate memory for buffer
*buffer = malloc(size + 1);
if (*buffer == NULL) {
fatal("Error allocating memory");
}
memset(*buffer, 0, size + 1);
// Read file and store data in buffer
fread(*buffer, 1, size, fp);
if (ferror(fp) != 0) {
fatal("Error reading file");
}
fclose(fp);
return size;
}
void socket_comm(char* buffer, long size) {
const char* PEER_SOCKET_PATH = "/home/tux/temp/server_sock";
int socket_fd;
// Create socket
socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd == -1) {
fatal(strerror(errno));
}
// Connect to server
struct sockaddr_un peer_socket_addr;
memset(&peer_socket_addr, 0, sizeof(struct sockaddr_un));
peer_socket_addr.sun_family = AF_UNIX;
strncpy(peer_socket_addr.sun_path, PEER_SOCKET_PATH, sizeof(peer_socket_addr.sun_path) - 1);
if (connect(socket_fd, (struct sockaddr*) &peer_socket_addr, sizeof(peer_socket_addr)) == -1) {
fatal("Error while connecting to server");
}
printf("Connected to server.\n");
// Send data to server
if (write(socket_fd, buffer, size) == -1) {
fatal("Error sending data to server");
}
return;
}
int main(int argc, char* argv[]) {
char* file_buffer;
long file_size;
// Get data and file size
file_size = get_data(argc, argv, &file_buffer);
// Send data to server
socket_comm(file_buffer, file_size);
// Free memory
free(file_buffer);
return 0;
}
Codes can be downloaded in my github repo.