为什么会发生"Address already in use"

Why "Address already in use" happens

本文关键字:already in use Address 为什么      更新时间:2023-10-16

我正在制作一个c++套接字应用程序。

可以连接android设备。

当我在接收数据时关闭手机连接…

Framebuffer Ready
[PCast] Waiting for connection
[PCast] Connected
....
[PCast] Data arrived
[PCast] *** Downloading mode ***
[PCast] Downloading file. Please wait...
[PCast:sock2file] Downloading...
[PCast:sock2file] Disconnection detected. Exiting sock2file.
[PCast] Disconnected
(Close client socket descriptor)
[PCast] Waiting for connection

看起来连接已成功关闭。但是当我重启服务器…

Framebuffer Ready
[PCast] Socket bind failed: Address already in use

当我的android应用程序试图连接(服务器没有运行),它说它连接到服务器。(数据传输不正常)

运行

netstat -anp

我可以看到我的端口处于CLOSE_WAIT状态。

...
tcp        1      0 172.30.1.3:5520         172.30.1.2:47144        CLOSE_WAIT  -               
tcp        0      0 172.30.1.3:22           172.30.1.1:50598        ESTABLISHED -               
tcp        1      0 172.30.1.3:5520         172.30.1.2:47202        CLOSE_WAIT  -     
...

代码(省略日志,韩文注释…):

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <linux/fb.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <signal.h>
#include "imgs.h"
using std::string;
#define FBDEV "/dev/fb0"
int scrsize, width, height;
int basesize;
#define CMD_GET_IP_ETH "/home/pi/scripts/ip.sh eth"
#define CMD_GET_IP_WLN "/home/pi/scripts/ip.sh wlan"
#define getPercent(total, current) (current / total) * 100
#define getLargeValue(org, b) (org * b) / 320
short *display;
short org[320*240];
//Convert images to char map
char strmap[128][5*5];
bool debug = false;
void cons_log(string message){
    printf("%sn", message.c_str());
}
void drawPixel(int x, int y, short col){
    if((width * y + x) < width * height){
        display[width*y+x] = col;
    }
}
short mkcolor(int r, int g, int b){
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
}
void writeImage(int sx, int sy, char img[], int size){
    size *= basesize;
    for(int y = 0; y < 5; y++) for(int x = 0; x < 5; x++){
        int prtx = sx + x * size, prty = sy + y * size;
        for(int rx = 0; rx < size; rx++) for(int ry = 0; ry < size; ry++){
            drawPixel(prtx + rx, prty + ry, img[5*y+x] * 0xffff);
        }
    }
}
void writeImage(char img[], int size){
    int centerX = width / 2 - 5 * size / 2;
    int centerY = height / 2 - 5 * size / 2;
    writeImage(centerX, centerY, img, size);
}
void writeMessage(int x, int y, string s, int size){
    size *= basesize;
    y += height / 2 - size * 5;
    for(int i = 0; i < s.length(); i++){
        int prtx = x + i * (size * 5);
        writeImage(prtx, y, strmap[s.at(i)], size / basesize);
    }
}
void writeMessage(int y, string s, int size){
    size *= basesize;
    int x = width / 2 - ((s.length()) * (size * 5)) / 2;
    y += height / 2 - size * 5;
    for(int i = 0; i < s.length(); i++){
        int prtx = x + i * (size * 5);
        writeImage(prtx, y, strmap[s.at(i)], size / basesize);
    }
}
void writeMessage(string s, int size){
    writeMessage(0, s, size);
}
void clear(){
    for(int i = 0; i < width * height; i++) display[i] = 0;
}
#define img_height(size) size * 5 * basesize
void printStandBy(bool connected){
    clear();
    writeMessage("pcast", 2);
    char buffer[100];
    FILE* pipe;
    pipe = popen("sh /home/pi/scripts/ip.sh eth", "r");
    fgets(buffer, 100, pipe);
    pclose(pipe);
    writeMessage(img_height(2) + 10, buffer, 1);
    memset(buffer, 0, 100);
    pipe = popen("sh /home/pi/scripts/ip.sh wlan", "r");
    fgets(buffer, 100, pipe);
    pclose(pipe);
    writeMessage(img_height(2) * 2 + 10, buffer, 1);
    if(connected){
        writeMessage(img_height(2) * 3 + 10, "connected", 1);
    }else{
        writeMessage(img_height(2) * 3 + 10, "not connected", 1);
    }
}
void printDownloading(){
    clear();
    writeImage(IMG_DOWNLOAD, 2);
    writeMessage(img_height(2) + 10, "downloading", 1);
}
int server_sockfd, client_sockfd;
void endHandler(int signo){
    if(client_sockfd != NULL) close(client_sockfd);
    if(server_sockfd != NULL) close(server_sockfd);
    exit(0);
}
bool sock2file(int socket){
    system("sudo rm /tmp/tmp");
    int count = 0;
    int file = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
    int totalBytes = 0;
    while(true){
        char buffer[1024*1024];
        int recvBytes = recv(socket, buffer, 1024*1024, MSG_DONTWAIT);
        if(recvBytes == 0){
            return false;
        }else if(recvBytes == -1){
            if(count == 5000){
                char send[] = {1, NULL};
                write(socket, send, 1);
                break;
            }else{
                usleep(1000);
                count++;
            }
        }else{
            count = 0;
            char send[] = {0, NULL};
            write(socket, send, 1);
            write(file, buffer, recvBytes);
            totalBytes += recvBytes;
            //byte to B/KB/MB/GB
            int displaySize = totalBytes;
            char sizeUnit = 'b';
            if(displaySize > 1024){
                displaySize /= 1024;
                sizeUnit = 'k';
            }
            if(displaySize > 1024){
                displaySize /= 1024;
                sizeUnit = 'm';
            }
            //Print current status
            char buf[100];
            sprintf(buf, "received %d%c    ", displaySize, sizeUnit);
            string status(buf);
            writeMessage(0, img_height(2) * 2 + 10, status, 1);
        }
    }
    return true;
}
int main(int argc, char **argv){
    if(argc == 2){
        if(!strcmp(argv[0], "d")) debug = true;
    }
    signal(SIGTERM, endHandler);
    signal(SIGINT, endHandler);
    memcpy(strmap['0'], IMG_0, 5*5);
    memcpy(strmap['1'], IMG_1, 5*5);
    memcpy(strmap['2'], IMG_2, 5*5);
    memcpy(strmap['3'], IMG_3, 5*5);
    memcpy(strmap['4'], IMG_4, 5*5);
    memcpy(strmap['5'], IMG_5, 5*5);
    memcpy(strmap['6'], IMG_6, 5*5);
    memcpy(strmap['7'], IMG_7, 5*5);
    memcpy(strmap['8'], IMG_8, 5*5);
    memcpy(strmap['9'], IMG_9, 5*5);
    memcpy(strmap['.'], IMG_DOT, 5*5);
    memcpy(strmap[':'], IMG_DOBULE_DOT, 5*5);
    memcpy(strmap['a'], IMG_A, 5*5);
    memcpy(strmap['b'], IMG_B, 5*5);
    memcpy(strmap['c'], IMG_C, 5*5);
    memcpy(strmap['d'], IMG_D, 5*5);
    memcpy(strmap['e'], IMG_E, 5*5);
    memcpy(strmap['f'], IMG_F, 5*5);
    memcpy(strmap['g'], IMG_G, 5*5);
    memcpy(strmap['h'], IMG_H, 5*5);
    memcpy(strmap['i'], IMG_I, 5*5);
    memcpy(strmap['j'], IMG_J, 5*5);
    memcpy(strmap['k'], IMG_K, 5*5);
    memcpy(strmap['m'], IMG_M, 5*5);
    memcpy(strmap['n'], IMG_N, 5*5);
    memcpy(strmap['l'], IMG_L, 5*5);
    memcpy(strmap['o'], IMG_O, 5*5);
    memcpy(strmap['p'], IMG_P, 5*5);
    memcpy(strmap['q'], IMG_Q, 5*5);
    memcpy(strmap['r'], IMG_R, 5*5);
    memcpy(strmap['s'], IMG_S, 5*5);
    memcpy(strmap['t'], IMG_T, 5*5);
    memcpy(strmap['u'], IMG_U, 5*5);
    memcpy(strmap['v'], IMG_V, 5*5);
    memcpy(strmap['w'], IMG_W, 5*5);
    memcpy(strmap['x'], IMG_X, 5*5);
    memcpy(strmap['y'], IMG_Y, 5*5);
    memcpy(strmap['z'], IMG_Z, 5*5);
    memcpy(strmap[' '], IMG_SPACE, 5*5);
    //Framebuffer Setup
    int fb_fd;
    fb_fd = open(FBDEV, O_RDWR);
    if(!fb_fd){
        exit(1);
    }
    fb_var_screeninfo fvsInfo;
    if(ioctl(fb_fd, FBIOGET_VSCREENINFO, &fvsInfo)){
        exit(1);
    }
    width = fvsInfo.xres;
    height = fvsInfo.yres;
    scrsize = width * height * 2;
    basesize = (width + height) / 2 / 100;
    display = (short *)mmap(0, scrsize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if((int *)display == -1){
        exit(1);
    }
    printStandBy(false);
    //Socket setup
    int state, client_len;
    int pid;
    struct sockaddr_in siClient, siServer;
    state = 0;
    client_len = sizeof(siClient);
    if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        exit(0);
    }
    bzero(&siServer, sizeof(siServer));
    siServer.sin_family = AF_INET;
    siServer.sin_addr.s_addr = htonl(INADDR_ANY);
    siServer.sin_port = htons(5520);
    state = bind(server_sockfd , (struct sockaddr *)&siServer, sizeof(siServer));
    if (state == -1){
        exit(0);
    }
    state = listen(server_sockfd, 5);
    if (state == -1){
        exit(0);
    }
    while(1){
        client_sockfd = accept(server_sockfd, (struct sockaddr *)&siClient,
                               &client_len);
        if (client_sockfd == -1){
            exit(0);
        }
        printStandBy(true);
        int avg;
        int orgtime = time(NULL);
        while(1){
            char datainfo[2];
            int recvBytes = recv(client_sockfd, datainfo, 2, MSG_WAITALL);
            if(recvBytes == 0 || recvBytes == -1) break;
            else{
                system("sudo killall omxplayer*");
                write(client_sockfd, datainfo, 2);
                //*** Downloading mode ***
                printDownloading();
                bool status = sock2file(client_sockfd);
                if(!status) break;
                printStandBy(true);
                system("nohup omxplayer /tmp/tmp &");
            }
        }
        printStandBy(false);
        close(client_sockfd);
    }
}
  • 程序没有崩溃。我退出了Ctrl + C(正如你所看到的,有一个处理程序Ctrl + C,杀死信号…)

  • 我的android应用程序退出时关闭连接

当远端异常关闭连接时,端口被绑定在TIME_WAIT状态,并且您不能重用(即重新绑定)它,除非超时已过期。您可以减少超时时间,设置套接字选项SO_REUSEADDR以强制重用端口,或者在重新启动服务器时等待端口被释放。

在监听套接字上设置SO_REUSEADDR选项将强制操作系统允许绑定端口,即使该端口正在使用中。这将解决您的症状,但不能解决根本原因,因此,如果确实有多个服务器在运行,则容易出现问题。

如果您的服务器在客户端到达FIN之前开始在TCP套接字上发送FIN,那么TCP状态机将强制它转换到TIME_WAIT状态。在您的情况下,您可能在客户端实际关闭连接之前使用CtrlC关闭服务器,因此服务器正在启动FIN。

既然你是强制关闭服务器,你可能宁愿在TCP套接字上发出RESET。在大多数TCP栈上,这是通过启用SO_LINGER选项并将超时值设置为0来实现的。您还可以在等待客户端发送某些内容时超时设置此参数。