[英]accept() call doesn't initialize sockaddr struct
I have written a short TCP server example in C which continually listens for connections on port 12701, and outputs the value of the peer's sockaddr.sa_family to stdout. 我用C语言编写了一个简短的TCP服务器示例,该示例不断侦听端口12701上的连接,并将对等方的sockaddr.sa_family的值输出到stdout。 The program calls accept() in an infinite loop, which should fill in a struct sockaddr
with the details of the connection, including sa_family. 程序在无限循环中调用accept(),该循环应在struct sockaddr
填充连接的详细信息,包括sa_family。
However, this doesn't happen correctly for the first TCP connection; 但是,对于第一个TCP连接,这种情况不会正确发生。 sockaddr.sa_family is always zero. sockaddr.sa_family始终为零。 All subsequent connections provide a correct value of two - only the first one is wrong. 所有后续连接均提供正确的值2-仅第一个错误。 Why does this happen? 为什么会这样? I haven't been able to find any reports of similar problems, but I suspect I am initializing something incorrectly or misinterpreting the parameters of accept(). 我没有找到类似问题的任何报告,但我怀疑我在初始化某些错误或误解了accept()的参数。
Here is the program: 这是程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(void)
{
struct sockaddr_in saddr =
{
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(12701),
};
// open socket to accept() tcp connections
int accept_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(accept_fd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in));
listen(accept_fd, SOMAXCONN);
socklen_t addrlen;
struct sockaddr * addr;
for(;;)
{
addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
int child_fd = accept(accept_fd, addr, &addrlen);
// why is this always zero the first time?
printf("addr->sa_family = %d\n", addr->sa_family);
close(child_fd);
free(addr);
}
return 0;
}
This assumes AF_INET
for the connection to be setup. 假定使用AF_INET
建立连接。
You want to pass to accept()
the address of a structure suitable to what you bound the listening socket to, that is a struct sockaddr_in
. 您想传递一个accept()
结构体的地址,该结构体适合于将侦听套接字绑定到的struct sockaddr_in
,即struct sockaddr_in
。
Also addrlen
needs to be set to the size of what the address of is passed to accept()
. 另外,还需要将addrlen
设置为传递给accept()
的地址的大小。
for (;;)
{
struct sockaddr_in * addr = malloc(sizeof *addr);
socklen_t addrlen = sizeof *addr;
if (NULL == addr)
{
perror("malloc() failed");
/* exit(), break, continue, whatever ... */
}
int child_fd = accept(accept_fd, (struct sockaddr *) addr, &addrlen);
if (-1 == child_fd)
{
perror("accept() failed");
free(addr);
addr = NULL;
/* exit(), break, continue, whatever ... */
}
/* Do stuff. */
close(child_fd);
free(addr);
}
the call to accept()
is not being handled correctly. 对accept()
的调用未正确处理。
in the posted code: 在发布的代码中:
accept()
must be checked for a failure. 必须检查对accept()
的调用是否失败。 malloc()
must be checked for a failure 必须检查对malloc()
的调用是否失败 addrlen
parameter to accept()
must be properly initialized before each call to accept()
. 在每次调用accept()
之前,必须正确初始化accept()
的addrlen
参数。 The posted code can only handle one connection at a time. 发布的代码一次只能处理一个连接。 It would be a good idea to allow for multiple simultaneous connections by having each connection be routed to a thread
. 通过将每个连接路由到一个thread
来允许多个同时连接是一个好主意。 However, generating/destroying threads takes a long time, so suggest having a 'pool' of threads that are initially set to 'unused' and passing each connection to a 'currently unused' thread, after marking that thread as 'in use' When the thread returns, mark it as 'unused', again. 但是,生成/销毁线程会花费很长时间,因此建议将该线程标记为“使用中”后,先将其初始设置为“未使用”的线程“池”并将每个连接传递给“当前未使用”的线程。线程返回,再次将其标记为“未使用”。
In the following code, no effort has been made to allow for multiple simultaneous connections. 在以下代码中,没有做出允许同时进行多个连接的努力。
for(;;)
{
addr = malloc(sizeof(struct sockaddr));
if( !addr )
{
perror( "malloc failed" );
exit( EXIT_FAILURE ); // exit() and EXIT_FAILURE from stdlib.h
}
// implied else, malloc successful
addrlen = sizeof( struct sockaddr );
int child_fd = accept(accept_fd, addr, &addrlen);
if( -1 == child_fd )
{ // then an error occurred
perror( "accept failed" );
}
else
{ // else, accept successful
printf("addr->sa_family = %d\n", addr->sa_family);
close(child_fd);
}
free( addr ); // to avoid memory leak
addr = NULL; // for safety
}
Take a look at for instance this documentation : http://man7.org/linux/man-pages/man2/accept.2.html 例如,看一下此文档: http : //man7.org/linux/man-pages/man2/accept.2.html
And more specifically the description of the addrlen parameter. 更具体地说,addrlen参数的描述。 This is an inout parameter and you must initialise it properly. 这是一个inout参数,您必须正确初始化它。
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; addrlen参数是一个值结果参数:调用者必须对其进行初始化,以包含addr指向的结构的大小(以字节为单位); on return it will contain the actual size of the peer address.' 返回时,它将包含对等地址的实际大小。”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.