这是我的代码的一部分,对于一个简单的echo服务器,我试图使用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
的新值不是有效套接字的结果。
还包含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);
}
答案 0 :(得分:2)
您的代码具有未定义的行为,如预期的那样。
int addrlen = sizeof(*addr), amount_read;
...
accept(fd, (struct sockaddr*)&addr, (socklen_t*)&addrlen));
首先,您正在获取addr
的地址,该地址已经是指针。你不应该这样做。
另外,我的小水晶球告诉我你在64位平台上,因此你的socklen_t
是64位整数。
要解决您的问题,请不要使用指针的地址并取消令人讨厌的演员并使用正确的类型。
socklen_t addrlen = sizeof(*addr);
...
accept(fd, (struct sockaddr*)addr, &addrlen);