首页 > 解决方案 > 没有建立连接时 TCP 服务器接受()连接

问题描述

编辑:问题已被发现。另一个服务正在使用相同的端口号在网络上运行。

以下服务器代码在 Raspbian Buster Lite (Debian 10) 下的 Pi 4 上运行,将 accept() 连接并接收客户端发送的数据并向客户端返回响应。然而,当它坐在 accept() 等待连接时,它会非常定期地认为连接已建立并读取相同的三个字节(0x1D 0x6E 0x02)。

这是一些示例输出:

pi@bps-dev:~/source $ ./a.out
Waiting for connection....
Connection established
1B 40 1B 1B 1B 40 1B 2E 00 45 4C 00 92 49 24 92   .@...@...EL..I$.
49 24 92 49 24 92 49 24 92 49 24 92 49 24 92 49   I$.I$.I$.I$.I$.I
24 92 49 24 92 49 24 92 49 24 92 49 24 92 49 24   $.I$.I$.I$.I$.I$
92 49 24 92 49 24 92 49 24 92 49 24 92 49 24 92   .I$.I$.I$.I$.I$.
49 24 92 49 24 92 49 24 92 49 24 92 49 24 92 49   I$.I$.I$.I$.I$.I
24 0A 0D 1B 2E 00 45 4C 00 49 24 92 49 24 92 49   $.....EL.I$.I$.I
24 92 49 24 92 49 24 92 49 24 92 49 24 92 49 24   $.I$.I$.I$.I$.I$
92 49 24 92 49 24 92 49 24 92 49 24 92 49 24 92   .I$.I$.I$.I$.I$.
49 24 92 49 24 92 49 24 92 49 24 92 49 24 92 49   I$.I$.I$.I$.I$.I
24 92 49 24 92 49 24 92 49 24 92 49 24 92 0A 0D   $.I$.I$.I$.I$...
1B 2E 00 45 4C 00 24 92 49 24 92 49 24 92 49 24   ...EL.$.I$.I$.I$
92 49 24 92 49 24 92 49 24 92 49 24 92 49 24 92   .I$.I$.I$.I$.I$.
49 24 92 49 24 92 49 24 92 49 24 92 49 24 92 49   I$.I$.I$.I$.I$.I
24 92 49 24 92 49 24 92 49 24 92 49 24 92 49 24   $.I$.I$.I$.I$.I$
92 49 24 92 49 24 92 49 24 92 49 0A 0D 0A 0D 0A   .I$.I$.I$.I.....
0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 1B   ................
76                                                v
Waiting for connection....
Connection established
1D 6E 02                                          .n.
Waiting for connection....
Connection established
1D 6E 02                                          .n.
Waiting for connection....
Connection established
1D 6E 02                                          .n.
Waiting for connection....
Connection established
1D 6E 02                                          .n.
Waiting for connection....
Connection established
1D 6E 02                                          .n.
Waiting for connection....

请注意所有“已建立连接”的已建立消息。我很确定实际上没有任何联系。虽然我还没有用 tcpdump 验证过。

accept() 和 read() 都不会返回错误。会发生什么?

这是代码:

#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>

#define PORT 9100
#define READ_CHUNK_SIZE         (1024)  /* read data in 1k blocks */


int msleep(long msec)
{
    struct timespec ts;
    int res;

    if (msec < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ts.tv_sec = msec / 1000;
    ts.tv_nsec = (msec % 1000) * 1000000;

    do
    {
        res = nanosleep(&ts, &ts);
    } while (res && errno == EINTR);

    return res;
}


void DEBUG_DumpMem( uint8_t *buffer, int length )
{
    int x;
    unsigned long bytes = 0;
    char outbuf[80];
    int hex_pos, asc_pos;
    uint8_t *ptr;
    int i;

    ptr = buffer;   
    hex_pos = 0;
    asc_pos = 50;
    memset(outbuf, ' ', sizeof(outbuf)-1);
    outbuf[79] = 0x00;
    for(i = 0; i<length; i++)
    {
            x = *(ptr+i);
            sprintf(&outbuf[hex_pos], "%02X ", x);
            outbuf[asc_pos++] = ( x >= 0x20 && x <= 0x7e ) ? (char)x : '.';

            outbuf[hex_pos+=3] = ' ';

            if(!((++bytes)%16))
            {
                printf("%s\n", outbuf);
                hex_pos = 0;
                asc_pos = 50;

                memset( outbuf, ' ', sizeof(outbuf)-1);
            }
    }
    printf("%s\n", outbuf);
}

uint8_t *SocketRead(int sockfd, int *bytesRead, int timeout)
{
    int size_recv = 0;
    int total_size = 0;
    struct timeval begin;
    struct timeval now;
    uint8_t *data = NULL;
    double timediff;

    // initially we will provide ourselves with a 275k buffer
    // which is more than large enough for a 3" x 8" rasterized image.
    data = malloc((size_t)READ_CHUNK_SIZE * 275);

    if( data != NULL )
    {
        // do first read without regard to timeout
        total_size = read(sockfd, data, READ_CHUNK_SIZE);
        if( total_size > 0 )
        {
            gettimeofday(&begin , NULL);
            while(1)
            {
                gettimeofday(&now , NULL);

                timediff = (now.tv_sec - begin.tv_sec) + 1e-6 * (now.tv_usec - begin.tv_usec);

                //received data and we hit our timeout. We will assume all data
                //has been read.
                if( total_size > 0 && timediff > timeout )
                {
                    break;
                }
                else if( timediff > timeout)
                {
                    // no data received and timeout occurred
                    break;
                }

                // TODO: We need to at some point make sure to realloc() the buffer if we have to read more than
                // 275k of data
                if((size_recv =  recv(sockfd, &data[total_size], READ_CHUNK_SIZE, MSG_DONTWAIT) ) > 0)
                {
                    total_size += size_recv;
                }
                msleep(100);
            }
        }
        else
        {
            if( total_size == -1 )
            {
                perror("read:");
            }
        }
    }

    *bytesRead = total_size;
    return data;
}



// This is the entry point upon which all processing and communication is done
// with the K20 docking board. It is expected that when this function returns the
// client is sent a response and the socket has been closed.
void HandleConnection(int sockfd)
{
    char response[] = "Status: Unknown";
    int bytesRead = 0;
    uint8_t *clientData = NULL;

    clientData = SocketRead(sockfd, &bytesRead, 2);
    DEBUG_DumpMem( clientData, bytesRead);
    free(clientData);

    // send response to client
    write(sockfd, response, sizeof(response));
    return;
}

int main(int argc, char *argv[])
{
    socklen_t len;
    int sockfd, connfd;
    struct sockaddr_in servaddr, client;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        perror("create socket:");
        exit(1);
    }

    memset(&servaddr, 0x00, sizeof(servaddr));

    // set IP and port number
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    int reuse = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
    {
        perror("setsockopt(SO_REUSEADDR) failed");
    }

    if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0)
    {
        perror("bind:");
        exit(1);
    }

    if ((listen(sockfd, 5)) != 0)
    {
        perror("listen:");
        exit(1);
    }

    len = (socklen_t)sizeof(client);
    while(1)
    {
        printf("Waiting for connection....\n");

        // Accept the data packet from client and verification
        connfd = accept(sockfd, (struct sockaddr*)&client, &len);
        if (connfd < 0)
        {
            //if(errno == EINTR)
            //{
            //  continue;
            //}
            perror("acccept:");
            //exit(1);
            continue;
        }
        else
        {
            printf("Connection established\n");
        }

        // Do all of the printing processing stuff in the function.
        // When this function returns the socket will be closed and another connection
        // can be accepted in the loop.
        HandleConnection(connfd);
    }
    close(sockfd);
    return(0);
}

标签: linuxsocketstcpservernetwork-programming

解决方案


导致问题的代码没有任何问题。它实际上是使用相同端口在网络上运行的另一个服务。


推荐阅读