server0451

Форк
0
/
sockets.c 
245 строк · 8.4 Кб
1
/******************* ОПИСАНИЕ *******************/
2

3
/**
4
 * Имя файла: sockets.c
5
 * ----------------------------------------------------------------------------|---------------------------------------|
6
 * Назначение: работа с сокетами TCP/IP.
7
 * ----------------------------------------------------------------------------|---------------------------------------|
8
 * Примечания:
9
 */
10

11

12
/************ ДИРЕКТИВЫ ПРЕПРОЦЕССОРА ***********/
13

14
/*--- Включения ---*/
15

16
// Из стандартной библиотеки языка Си.
17
#include <stdio.h>
18
#include <inttypes.h>
19
#include <string.h>
20

21
// Из библиотек POSIX.
22
#include <unistd.h>
23
#include <netinet/in.h>
24
#include <signal.h>
25

26
/* Эти заголовочные файлы упоминаются в примерах серверов, написанных
27
 * на языке Си, но код компилируется и работает и без них. Оставляю на память.
28
 */
29
//#include <netdb.h>
30
//#include <sys/socket.h>
31
//#include <sys/types.h>
32

33
// Настройки.
34
#include "config_general.h"
35

36
// Локальные модули.
37
#include "sockets.h"
38
#include "utilities.h"
39
#include "timestamp.h"
40

41
/******************** ФУНКЦИИ *******************/
42

43
uint32_t sockets_init(int32_t *sockfd, int32_t port, uint32_t numconn, uint32_t verbosity_level)
44
{
45
    /*--- Создание сокета ---*/
46

47
    *sockfd = socket(AF_INET, SOCK_STREAM, 0);
48
    if (*sockfd < 0) {
49
        return SOCKETS_INIT_ERR_CREATE;
50
    } else if (verbosity_level > 0) {
51
        printf("\n...socket successfully created.\n");
52
    }
53

54

55
    /*--- Установка опций сокетов ---*/
56

57
    /* Условной компиляцией можно управлять с помощью соответствующих директив,
58
     * приведённых в файле config_general.h.
59
     */
60

61
    #ifdef SOCKOPT_SO_REUSEPORT
62
        /* Разрешение заново использовать сочетание порта и адреса
63
         * немедленно после закрытия предыдущего соединения.
64
         * Если это делается, то обязательно до вызова bind().
65
         */
66
        int32_t so_reuseport = 1;
67
        int32_t so_reuseport_result = setsockopt(*sockfd,
68
                                                 SOL_SOCKET,
69
                                                 SO_REUSEPORT,
70
                                                 &so_reuseport,
71
                                                 (socklen_t)sizeof(so_reuseport));
72

73
        if (so_reuseport_result != 0) {
74
            return SOCKETS_INIT_ERR_SETSOCKOPT;
75
        } else if (verbosity_level > 1) {
76
            printf("...setting SO_REUSEPORT socket option. Success.\n");
77
        }
78
    #endif
79

80
    #ifdef SOCKOPT_SO_REUSEADDR
81
        /* Разрешение заново использовать адрес
82
         * немедленно после закрытия предыдущего соединения.
83
         * Если это делается, то обязательно до вызова bind().
84
         */
85
        int32_t so_reuseaddr = 1;
86
        int32_t so_reuseaddr_result = setsockopt(*sockfd,
87
                                                 SOL_SOCKET,
88
                                                 SO_REUSEADDR,
89
                                                 &so_reuseaddr,
90
                                                 (socklen_t)sizeof(so_reuseaddr));
91

92
        if (so_reuseaddr_result != 0) {
93
            return SOCKETS_INIT_ERR_SETSOCKOPT;
94
        } else if (verbosity_level > 1) {
95
            printf("...setting SO_REUSEADDR socket option. Success.\n");
96
        }
97
    #endif
98

99
    #ifdef SOCKOPT_SO_LINGER
100
        /* Установка времени ожидания полной передачи данных.
101
         * Если это делается, то обязательно до вызова bind().
102
         */
103
        struct linger so_linger;
104
        so_linger.l_onoff = 1;
105
        so_linger.l_linger = L_LINGER;
106
        int32_t so_linger_result = setsockopt(*sockfd,
107
                                              SOL_SOCKET,
108
                                              SO_LINGER,
109
                                              &so_linger,
110
                                              (socklen_t)sizeof(so_linger));
111

112
        if (so_linger_result != 0) {
113
            return SOCKETS_INIT_ERR_SETSOCKOPT;
114
        } else if (verbosity_level > 1) {
115
            printf("...setting SO_LINGER socket option, specified linger time is %d sec. Success.\n",
116
                   so_linger.l_linger);
117
        }
118
    #endif
119

120

121
    /*--- Связка вновь созданного сокета и адреса ---*/
122

123
    struct sockaddr_in serveraddr;
124

125
    // Заполнение структуры нулями.
126
    memset(&serveraddr, '\0', sizeof(serveraddr));  /* Иногда используют функцию bzero(),
127
                                                     * но она считается устаревшей.
128
                                                     */
129

130
    serveraddr.sin_family = AF_INET;
131
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
132
    serveraddr.sin_port = htons(port);
133

134
    if (bind(*sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) != 0) {
135
        return SOCKETS_INIT_ERR_BIND;
136
    } else if (verbosity_level > 0) {
137
        printf("...socket successfully bound.\n");
138
    }
139

140

141
    /*--- Связка вновь созданного сокета и адреса ---*/
142

143
    if (listen(*sockfd, numconn) != 0) {
144
        return SOCKETS_INIT_ERR_LISTEN;
145
    } else if (verbosity_level > 0) {
146
        printf("...server is listening.\n");
147
    }
148

149
    return SOCKETS_INIT_OK;
150
}
151

152
uint32_t sockets_proceed(int32_t sockfd, int32_t *connfd, uint32_t timeout_sec, uint32_t verbosity_level)
153
{
154
    /*--- Установка связи с клиентом ---*/
155
    
156
    int32_t socklen = 0;
157
    struct sockaddr_in clientaddr;
158

159
    socklen = sizeof(clientaddr);
160
    *connfd = accept(sockfd, (struct sockaddr*)&clientaddr, (socklen_t*)&socklen);
161
    if (*connfd < 0) {
162
        return SOCKETS_PROCEED_ERR_ACCEPT;
163
    } else if (verbosity_level > 0) {
164
        printf("\nServer accepted a client, waiting for incoming data. ");
165
        timestamp_print();
166
        printf(".\n");
167
        fflush(stdout);
168
    }
169

170

171
    /*--- Проверка наличия данных в сокете ---*/
172
    
173
    struct timeval tv;
174
    tv.tv_sec = timeout_sec;
175
    tv.tv_usec = 0;
176
                   
177
    fd_set readfds;
178
    FD_ZERO(&readfds);
179
    FD_SET(*connfd, &readfds);
180

181
    int32_t result = select(*connfd + 1, &readfds, NULL, NULL, &tv);
182
    int32_t retval = -1;
183

184
    if (result < 0) {
185
        retval = SOCKETS_PROCEED_ERR_SELECT;
186
    } else if (result == 0) {
187
        retval = SOCKETS_PROCEED_TIMEOUT;
188
        if (verbosity_level > 0) {
189
            printf("\nConnection closed due to timeout.\n");
190
        }
191
    } else if (result > 0) {
192
        retval = SOCKETS_PROCEED_OK;
193
    }
194

195
    return retval;
196
}
197

198
void sockets_read_message(int32_t connfd, char *buf, size_t buf_size, uint32_t verbosity_level)
199
{
200
    // Чтение сообщения от клиента и его запись в буфер.
201
    read(connfd, buf, buf_size);
202
    utilities_nullify_all_trailing_CR_and_LF_in_string(buf);
203

204
    // Вывод содержимого буфера.
205
    if (verbosity_level > 0) {
206
        printf("\nMessage received from the client: %s\n", buf);
207
    }
208
}
209

210
void sockets_write_message(int32_t connfd, char *buf, uint32_t verbosity_level)
211
{
212
    utilities_nullify_all_trailing_CR_and_LF_in_string(buf);
213

214
    strcat(buf, "\n");
215
    write(connfd, buf, strlen(buf));
216

217
    utilities_nullify_all_trailing_CR_and_LF_in_string(buf);
218

219
    if (verbosity_level > 0) {
220
        printf("\nMessage sent to the client: %s\n", buf);
221
    }
222
}
223

224
int32_t sockets_close(int32_t fd, uint32_t pause)
225
{
226
    //shutdown(fd, SHUT_RDWR);  // Вроде не обязательно, хотя иногда рекомендуют.
227
    usleep(pause);
228
    int32_t retval = close(fd);
229
    usleep(pause);
230

231
    return retval;
232
}
233

234
void sockets_report_broken_pipe(int32_t sig)
235
{
236
    if (sig == SIGPIPE) {
237
        fprintf(stderr, "\n"
238
                        "Error: a client had disconnected before any response was sent by the server (broken pipe).\n");
239
    }
240
}
241

242
void sockets_sig_ign()
243
{
244
    signal(SIGPIPE, sockets_report_broken_pipe);
245
}
246

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.