UDP服务器没有响应客户端

时间:2014-03-24 17:37:16

标签: c udp

处理旨在模拟网络中数据层的程序。我已经正确地将消息传递到服务器,但是,客户端没有从服务器接收ACK帧。这导致我的程序无休止地等待。任何帮助解决问题的人都表示赞赏。

发件人

#include <stdio.h>
#include <unistd.h>
#define MAXFRAME  97
main(int argc, char* argv[]){
    char *frame;
    int len = 0;
    int c;
    dlinits("spirit.cba.csuohio.edu", 43525);
    frame = malloc(MAXFRAME);

    FILE *file = fopen(argv[1], "r");
    if (file == NULL)
        return NULL;

    while ((c = fgetc(file)) != EOF)
    {
        if(len == (MAXFRAME-1)){
            dlsend(frame, len, 0);
            len = 0;
            memset(frame,0,strlen(frame));
        }       

        frame[len++] = (char) c;
    }

    dlsend(frame, len, 1);




}

接收机

#include <string.h>
#include <unistd.h>
char* dlrecv();

main(){
    char* test[100];
    dlinitr(43525);
    while(1){
        strcpy(test,dlrecv());

        printf("%s\n", test);
    }


}

数据层

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFMAX 100

static int sk;
static struct sockaddr_in remote;
static struct sockaddr_in local;
static int fnum = 0;
static expFra = 0x00;

dlinits(char* host, int port){//initialize sender

    struct hostent *hp;
    sk = socket(AF_INET, SOCK_DGRAM, 0);

    remote.sin_family = AF_INET;

    hp = gethostbyname(host);
    if (hp == NULL){
        printf("Can't find host name\n");
        exit(1);
    }

    bcopy(hp->h_addr,&remote.sin_addr.s_addr,hp->h_length);

    remote.sin_port = ntohs(port);
}

dlinitr(int port){//initialize receiver
    int rlen = sizeof(remote);
    int len = sizeof(local);
    char buf[BUFMAX];

    sk = socket(AF_INET,SOCK_DGRAM,0);

    local.sin_family = AF_INET;
    local.sin_addr.s_addr = INADDR_ANY;
    local.sin_port = htons(port);
    bind (sk, &local,sizeof(local));

    getsockname(sk,&local,&len);

}

dlsend(char* msg, int len, int end){//send data
    int header = 0x00;
    int result;
    char *ackframe = malloc(3);
    unsigned char *nmsg;
    nmsg = malloc(100);
    if ((fnum%2) == 1){
        header = header|0x02;
    }
    if (end == 1){
        header = header|0x40;
    }
    header = header^0xff;
    printf("%x\n %x\n", header, 0);
    nmsg[0] = (char)header;
    len++;
    printf("%s\n", nmsg);
    memcpy(nmsg + 1, msg, strlen(msg));
    result = crc(nmsg, len);
    nmsg[len++] = ((result >> 8) & 0xff);
    nmsg[len++] = (result & 0xff);


    printf("%s\n", nmsg);
    sendto(sk,nmsg,len,0,&remote,sizeof(remote));

    read(sk,ackframe,3);
    printf("Ack Received: %s\n", ackframe);

    fnum++;
} 

char* dlrecv(){//receive data
    int result;
    int header;
    int ACK = 1;
    char alen = 1;
    char *ackframe = malloc(3);
    unsigned char* msg = malloc(100);
    while (ACK){
        recvfrom(sk,msg,BUFMAX,0,&remote,sizeof(remote));
        int len = strlen(msg);
        result = crc(msg, len);
        if (result == 0){
            msg[--len] = 0;
            msg[--len] = 0;
            header = msg[0];
            printf("Header %x expFra %x\n", header, expFra);
            header = header^0xff;
            printf("Header %x expFra %x\n", header, expFra);
            if ((header<<4) == (expFra<<4)){
                expFra = expFra^0x02;
                ackframe[0] = (0x10|header);
                result = crc(ackframe, alen);
                ackframe[alen++] = ((result >> 8) & 0xff);
                ackframe[alen++] = (result & 0xff);
                sendto(sk,ackframe,strlen(ackframe),0,&remote,sizeof(remote));
                printf("Ack Sent: %s\n", ackframe);
                ACK = 0;

            }
        }
    }
    printf("%s\n", msg);
    return ++msg;
}

编辑目前这些都在同一台机器上运行。 编辑我使用errno运行了一个检查,它为dlrecv中的sendto返回了错误22。

1 个答案:

答案 0 :(得分:2)

我对UDP的体验是read()(您在dlsend()结束时使用的)非常轻松,特别是与{{1}配对时}。除非有充分的理由不这样做,否则将sendto()更改为read()可以解决问题。

您的代码也会针对不匹配的类型抛出 lot 警告。他们有点无害,但跟踪其他任何事情都会变得更加复杂。

之后,最终确认 - recvfrom()正在使用错误的套接字数据。四处寻找,原因是您在(sendto())中传递了一个整数作为指向前一个sizeof(remote)调用中地址大小的指针。如果给定的初始大小太小,recvfrom()会产生不可靠的结果。如果它需要的空间少于此值,它会改变该值以告诉您它的用途。

因此,您需要声明一个整数,初始化为recvfrom()结构的大小,并将指针作为最后一个参数传递给它。通过这些更改,假设服务器到达sockaddr_in函数(您的样本只在单个条件分支下),您将获得正确的地址值并能够发送确认。

学到的重要经验应该是:(a)确保所有类型都正确并检查每个警告;(b)检查每个套接字调用的返回值,如果得到sendto(),则打印错误。