java - 在客户端更改网络 IP 后,可以从 Android(客户端)在 C(服务器)中发送但不能接收

标签 java android c sockets tcp

编辑:首先,我知道什么是 TCP 和 UDP,以及它们之间的区别,但是如何解释我能够在客户端上从服务器接收,但不能发送,如下所示...?

我用 C 语言制作了一个服务器应用程序,并用 Java 制作了一个客户端应用程序,并将其部署到 Android。 我有一个奇怪的问题,我无法克服。

当我的手机 IP 改变时(例如当切换到移动网络、从 Wifi 或反之亦然时),C 中的应用程序不再能够接收数据,只能发送,即使手机发送了数据,也没有任何错误.

重新连接到同一网络时不会发生这种情况。

我尝试了很多东西,最后在 C 中得到了这个:

void *receive_thread(){
    pthread_detach(pthread_self());

    struct sockaddr_in dest; /* socket info about the machine connecting to us */
    struct sockaddr_in serv; /* socket info about our server */
    int mysocket;            /* socket used to listen for incoming connections */
    socklen_t socksize = sizeof(struct sockaddr_in);

    memset(&serv, 0, sizeof(serv));           /* zero the struct before filling the fields */
    serv.sin_family = AF_INET;                /* set the type of connection to TCP/IP */
    serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
    serv.sin_port = htons(PORTNUMRCV);           /* set the server port number */    

    mysocket = socket(AF_INET, SOCK_STREAM, 0);

    //fcntl(mysocket, F_SETFD, O_NONBLOCK);

    /* bind serv information to mysocket */
    bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));

    /* start listening, allowing a queue of up to 1 pending connection */
    listen(mysocket, 1);

    int consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
    while(consocket){
        //socklen_t fromlen;
        //fromlen = sizeof inet_ntoa(dest.sin_addr);
        char receivemsg[128];

        int rlen = recv(consocket, &receivemsg, 128, 0); //receive data
        int err = errno;
        //printf("recv error: %d\n", err);
        printf("Received string: %s from %s \n", receivemsg, inet_ntoa(dest.sin_addr));
        if(rlen > 0){
            receivemsg[rlen] = '\0';
            if(comparestr(KEY, receivemsg) == 1){
                printf("Local client\n");
                incrementor++;
            } else if(comparestr(KEY, receivemsg) == 2){
                printf("Remote client\n");
                incrementor--;
            } else {
                printf("Wrong key!\n");
            }
        } else {
            printf("Care!!!! Receiving: %d \n", rlen);
        }
        close(consocket);
        consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
    }
    printf("Receive thread ended!\n");
    receive_thread_up = 0;
}

void *send_thread(){
    pthread_detach(pthread_self());

    struct sockaddr_in dest; /* socket info about the machine connecting to us */
    struct sockaddr_in serv; /* socket info about our server */
    int mysocket;            /* socket used to listen for incoming connections */
    socklen_t socksize = sizeof(struct sockaddr_in);

    memset(&serv, 0, sizeof(serv));           /* zero the struct before filling the fields */
    serv.sin_family = AF_INET;                /* set the type of connection to TCP/IP */
    serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
    serv.sin_port = htons(PORTNUMSND);           /* set the server port number */

    mysocket = socket(AF_INET, SOCK_STREAM, 0);

    /* bind serv information to mysocket */
    bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));

    /* start listening, allowing a queue of up to 1 pending connection */
    listen(mysocket, 1);

    int consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
    while(consocket){
        //printf("Incoming connection from %s - sending string\n", inet_ntoa(dest.sin_addr));
        int slen = send(consocket, KEY, 3*sizeof(KEY), 0); //send data
        if(slen>0)printf("Sent string: %s to %s \n", KEY, inet_ntoa(dest.sin_addr));
        else {
            printf("Care!!! Sending: %d \n", slen);
        }       
        close(consocket);
        consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
    }
    printf("Send thread ended!\n");
    send_thread_up = 0;
}

还有这个,在 Java 中:

public static int sendString(String str) throws IOException{
    System.out.println("Sending string: " + str);
    out.println(str);
    return 0;
}

public static String receiveString(){
    String s = " ";
    try {
        s = in.readLine();
    } catch (SocketException e) {
        System.out.println("Socket Exception: " + e);
    } catch (IOException e) {
        System.out.println("IOException on receive: " + e);
    }
    System.out.println("Received string: " + s);
    return s;
}
public static String reverseString(String str){
    String newStr = " ";
    newStr = new StringBuilder(str).reverse().toString();
    return newStr;
}

我的猜测是 recv 卡住了,因此我尝试添加

fcntl(mysocket, F_SETFD, O_NONBLOCK);

,在不起作用之后,我评论了它。 也许使用 UDP 套接字?我可能会遇到消息未到达或不完整等问题。 也欢迎提出改进我的代码的建议!

这是 C 中的输出:

Thread: No connection, waiting...
Sent string: I4mP4ssw0rd7 to 192.168.1.2
Received string: I4mP4ssw0rd7
 from 192.168.1.2
Local client
Sent string: I4mP4ssw0rd7 to 192.168.1.2
Thread: Local connection!
Received string: I4mP4ssw0rd7
 from 192.168.1.2
Local client
Sent string: I4mP4ssw0rd7 to 192.168.1.2
Sent string: I4mP4ssw0rd7 to 87.edited
Sent string: I4mP4ssw0rd7 to 87.edited
Sent string: I4mP4ssw0rd7 to 87.edited
Sent string: I4mP4ssw0rd7 to 87.edited
Sent string: I4mP4ssw0rd7 to 87.edited

这是 Java 的输出:

03-18 22:52:45.831  13899-13899/willymatica.alarmapp1 I/System.out﹕ Connected!
03-18 22:52:49.375  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected locally!
03-18 22:52:49.585  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:52:54.900  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: I4mP4ssw0rd7
03-18 22:52:54.910  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected locally!
03-18 22:52:54.970  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:00.265  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: I4mP4ssw0rd7
03-18 22:53:00.285  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected locally!
03-18 22:53:00.315  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:05.631  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: I4mP4ssw0rd7
03-18 22:53:05.631  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected remotely!
03-18 22:53:05.851  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:11.266  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: 7dr0wss4Pm4I
03-18 22:53:11.286  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected remotely!
03-18 22:53:11.516  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:16.912  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: 7dr0wss4Pm4I
03-18 22:53:16.932  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected remotely!
03-18 22:53:17.162  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:22.547  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: 7dr0wss4Pm4I
03-18 22:53:22.567  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected remotely!
03-18 22:53:23.198  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7
03-18 22:53:28.933  13899-13920/willymatica.alarmapp1 I/System.out﹕ Sending string: 7dr0wss4Pm4I
03-18 22:53:28.933  13899-13920/willymatica.alarmapp1 I/System.out﹕ Connected remotely!
03-18 22:53:29.113  13899-13920/willymatica.alarmapp1 I/System.out﹕ Received string: I4mP4ssw0rd7

最佳答案

TCP 是面向连接的。一旦建立了 TCP 连接,您就会得到所谓的套接字对。 Socket 对是源 ip 地址和源端口以及目标 ip 地址和目标端口的组合。连接由这 4 个参数唯一标识。

在整个 session 期间,将使用相同的 ip 地址和端口。

因此,如果一个网络接口(interface)不再可用,您就会遇到问题,因为每个网络接口(interface)都会有一个 IP 地址,如果它不再可用,则 TCP 连接将无法再选择其他网络接口(interface)。

TCP 不支持更改连接两端的 IP 地址。

需要相当长的时间才能检测到有问题。你认为你仍然可以发送,但是,TCP 会重传几次,最终你会看到发送失败。这甚至需要几分钟。根据您的套接字是否阻塞,您会注意到发送将在 IP@ 已更改的错误情况下阻塞。从 TCP 的角度来看,这就像断线。

关于java - 在客户端更改网络 IP 后,可以从 Android(客户端)在 C(服务器)中发送但不能接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29134010/

相关文章:

java - 完全反编译java6 web应用

java - 如何在 wicket 中使用具有月份和年份增量选项的 DatePicker?

android - 如何使用 ExoPlayer 获取正在播放的当前轨道的索引

c - 指示对 Clang 的未对齐访问以实现 ARM 兼容性

c - C 中的 64 位散列/摘要

java - GetRequest 中带有 2 个参数的 SQL 查询

java - 为什么 jmf 不能播放 rtp 流?

android - 如何使我的自定义微调器像默认微调器一样?

android - 当设备处于横向时拍摄人像照片有问题吗?

c - 为什么 C 代码不返回结构?