В общем-то этот пост создан для того, чтобы не потерять название книги:
Создание сетевых приложений в среде Linux. Руководство разработчика. Шон Уолтон.
Хорошая литература, посвященная сокетам в GNU/Linux и межсетевому протоколу IP (особое внимание уделено TCP и UDP). Затрагиваются нюансы многопоточного программированию для сетевых программок, шифрование и другие вопросы.
Ну а в качестве бонуса — простейшая программка, которую я применял для тестов работоспособности домашней сети. Использует для передачи датаграммы, соответственно протокол UDP. Поддерживать соединение с сервером не нужно — просто шлём в никуда сообщение. Проще пример не сделать.
Для тестов на одном компьютере можно использовать ip-адрес localhost’a 127.0.0.1. На двух устройствах — придётся указать реальный адрес сервера в программе клиента. Для компиляции не нужно подключать посторонних библиотек, всё как обычно:
gcc cli.c -o cli
gcc ser.c -o ser
Клиентская часть (cli.c)
#include
#include
#include
#include
#include
#include
#include
/* адрес сервера для связи */
#define ADDRESS "127.0.0.1"
/* порт сервера для связи
свой клиент получит от ОС автоматически*/
#define PORT = 10001;
int main(){
/*сообщения для передачи
uint8_t используется из-за размера
8 бит или ровно 1 байт*/
uint8_t test_msg[4] = {1, 2, 3, 4};
/*дескриптор сокета*/
int socket_des;
/*структура адреса для протокола IP для сервера*/
struct sockaddr_in server_addr;
/* создаём сокет и получаем его дескриптор: */
if((socket_des = socket(PF_INET, SOCK_DGRAM, 0)) < 0){
perror("Socket error: ");
exit(EXIT_FAILURE);
}
/* создаем адрес для отправки сообщения серверу*/
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_aton(ADDRESS, &server_addr.sin_addr);
/*отправка сообщения и проверка результата*/
if(sendto(socket_des, test_msg, sizeof(test_msg), 0,
(struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
perror("Send error:");
exit(EXIT_FAILURE);
}
/*закрываем сокет и завершаем работа*/
close(socket_des);
exit(EXIT_SUCCESS);
}
Серверная часть (ser.c)
#include
#include
#include
#include
#include
#include
/*порт сервера*/
#define PORT 10001
int main(){
int i;
/*полученное сообщение и его размер*/
uint8_t msg[4];
int msg_size;
/*дескриптор сокета*/
int socket_des;
/*структура с адресом сервера и клиента*/
struct sockaddr_in server_addr, client_addr;
int addr_size = sizeof(client_addr);
/* создаём сокет и получаем его дескриптор: */
if((socket_des = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket error: ");
exit(EXIT_FAILURE);
}
/*заполняем структуру с адресом сервера
необходимо для функции bind()*/
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
/*закрепляем определённый порт за сокетом*/
if(bind(socket_des, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0){
perror("bind error: ");
exit(EXIT_FAILURE);
}
/*бесконечный цикл*/
for(;;){
/*получаем сообщение от сервера, оно может быть меньше, но не
больше чем размер массива msg*/
msg_size = recvfrom(socket_des, msg, sizeof(msg), 0,
(struct sockaddr*)&client_addr, &addr_size);
/*печатаем длину сообщения и переданные байтики*/
printf("Длина полученного сообщения: %d\n", msg_size);
printf("Сообщение от клиента:\n");
for(i = 0; i < msg_size; i++)
printf("%d\n", msg[i]);
}
/*закрываем сокет и завершаем работу программы
в данном примере до этого никогда не дойдёт, а надо бы =(*/
close(socket_des);
exit(EXIT_SUCCESS);
}