Вот часть моего кода, для простого эхо-сервера, который я пытаюсь написать, используя системные вызовы сокетов linux:
while (true) {
std::cout << "Fd before accept: " << fd << std::endl;
if ((current_socket = accept(fd, (struct sockaddr*)&addr, (socklen_t*)&addrlen)) < 0) {
std::perror("accept");
exit(EXIT_FAILURE);
}
std::cout << "Accepted (fd) = " << fd << std::endl;
amount_read = read(current_socket, in_buf, 1024);
std::cout << "Amount read: " << amount_read << std::endl;
std::cout << "In from client: " << in_buf << std::endl;
std::cout << "What would you like to say back: ";
std::getline(std::cin, out_buf);
send(current_socket, out_buf.c_str(), out_buf.length(), 0);
std::cout << "Sent." << std::endl;
std::cout << "fd before looping = " << fd << std::endl;
}
Непосредственно перед этим фрагментом кода я настроил дескриптор сокета fd
, а затем, непосредственно перед началом цикла while:
listen(fd, 4);
Я компилирую это, затем запускаю и запускаю клиентскую программу, которую я написал для отправки сообщения ("Hello from the client"
)на сервер.
Моя проблема
В любом случае, моя проблема с этим заключается в том, что, как следует из заголовка, вызов accept(...)
изменяет значение fd
.Прежде всего, я не могу понять, как это возможно - fd
не передается как указатель, так как это может быть изменено вызовом функции?Но этот момент в основном представляет интерес - главное значение этой проблемы описано в следующем разделе.
Я уверен, что значение fd
было изменено, потому что приведен пример вывода с сервера:
Attempting to listen
Listening
Fd before accept: 3
Accepted (fd) = 0
Amount read: 17
In from client: Hello from client
What would you like to say back: ?
Sent.
fd before looping = 0
Fd before accept: 0
accept: Socket operation on non-socket
Итак, как вы можете видеть, fd
до вызова на прием составляет 3 , но затем после вызова становится 0
.
Почемуэто проблема
Возвращаясь к выводу с сервера, как показано выше:
accept: Socket operation on non-socket
Что явно является результатом того, что новое значение fd
не является действительнымsocket.
То, что я пробовал
Включая также listen(...)
вызов в цикле while(true) {...}
, на всякий случай, если мне нужно снова прослушивать каждого клиента.Я сомневался, что это сработает, и это не так.У меня все без идей.
Другие вопросы, которые не помогли
Я нашел где-то вопрос, спрашивающий, почему accept(...)
было , возвращая ( нет изменение параметра fd
) значение 0. Я понимаю, что 0 является допустимым дескриптором сокета, но, очевидно, здесь это не так.Кроме того, этого просто не должно происходить, верно?
Мой вопрос
Просто подведу итог: почему accept(...)
изменяет один из параметров, не являющихся указателями, и как я могу исправитьэто?
полный код
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <cstdint>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
int create_socket(uint16_t port, struct sockaddr_in* addr) {
int server_fd;
int opt = 1;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
std::perror("Socket create failed.");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
std::perror("setsockopt failed");
exit(EXIT_FAILURE);
}
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = INADDR_ANY;
addr->sin_port = htons(port);
// now bind it to a port
if (bind(server_fd, (struct sockaddr*)addr, sizeof(*addr)) < 0) {
std::perror("bind failed");
}
return server_fd;
}
int serve(int fd, struct sockaddr_in* addr, int backlog=4) {
std::string to_send;
int addrlen = sizeof(*addr), amount_read;
int current_socket;
char in_buf[1024];
std::string out_buf;
std::cout << "Attempting to listen" << std::endl;
if (listen(fd, backlog) < 0) {
std::perror("listen failed");
exit(EXIT_FAILURE);
}
std::cout << "Listening" << std::endl;
while (true) {
std::cout << "Fd before accept: " << fd << std::endl;
if ((current_socket = accept(fd, (struct sockaddr*)&addr, (socklen_t*)&addrlen)) < 0) {
std::perror("accept");
exit(EXIT_FAILURE);
}
std::cout << "Accepted (fd) = " << fd << std::endl;
amount_read = read(current_socket, in_buf, 1024);
std::cout << "Amount read: " << amount_read << std::endl;
std::cout << "In from client: " << in_buf << std::endl;
std::cout << "What would you like to say back: ";
std::getline(std::cin, out_buf);
send(current_socket, out_buf.c_str(), out_buf.length(), 0);
std::cout << "Sent." << std::endl;
std::cout << "fd before looping = " << fd << std::endl;
}
return 0;
}
int main(int argc, char* argv[]) {
struct sockaddr_in addr;
int fd = create_socket(5555, &addr);
serve(fd, &addr);
close(fd);
}