【问题标题】:Implementing Stop and wait with C & UDP, and what does cause 'resource temporarily unavailable'?使用 C 和 UDP 实现停止和等待,是什么导致“资源暂时不可用”?
【发布时间】:2015-10-15 06:43:50
【问题描述】:

我正在使用 c 和 udp 套接字编程实现停止和等待。为了模拟这个协议,我写了两个代码。

这是我的server.c 文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>


typedef struct packet{
    char data[1024];
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int main(int argc, char** argv)
{
    int sockfd;
    int clilen;
    int state;
    int n;
    int sum;
    int recv_result;

    int frame_id = 0;

    Packet packet;
    Frame frame;
    Frame recv_frame;
    char buffer[1024] = "";

    struct timeval tv;

    struct sockaddr_in serveraddr, clientaddr;

    FILE* infile = fopen(argv[2], "r");
    if(argc != 3)
    {
        perror("error! usage: $./server <PORT> filename\n");
        exit(1);
    }
    if(infile == NULL)
    {
        printf("error! failed to open the file.\n");
        exit(0);
    }

    clilen = sizeof(clientaddr);
    sockfd = socket(AF_INET, SOCK_DGRAM, 0); //using diagram instead of stream-- UDP
    if(sockfd < 0)
    {
        perror("socket error: ");
        exit(0);
    }

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1])); //set port number 9999

    //set socket option -- timeout is 100000 microseconds

    tv.tv_sec = 1;
    tv.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));

    state = bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    if(state == -1)
    {
        perror("bind error: ");
        exit(0);
    }

    do{
        n = fscanf(infile, "%s", buffer);

        strcpy(packet.data, buffer);
        memcpy(&(frame.packet), &packet, sizeof(Packet));
        frame.frame_kind = 1; //SEQ
        frame.sq_no = frame_id;
        frame.ack = 0;
        printf("flag2");
        while(1)
        {
            sendto(sockfd, &frame, sizeof(frame), 0, (struct sockaddr*)&clientaddr, (socklen_t)clilen);
            printf("Frame %d sent\n", frame_id);
            recv_result = recvfrom(sockfd, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&clientaddr, &clilen );

            if(recv_result > 0 && recv_frame.sq_no == 0 && recv_frame.ack == frame_id){
                printf("Ack %d received\n", recv_frame.sq_no);
                break;
            }else{
                printf("Frame %d time expired\n", frame_id);
            }
        }
        frame_id++;
    }while(n > 0);

    printf("finished\n");
    return 0;
}

这是我的client.c 文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

typedef struct packet{
    char data[1024];
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int main(int argc, char *argv[])
{
    int sock;
    int str_len;
    socklen_t adr_sz;
    FILE* outfile = fopen("output.txt", "w");
    struct sockaddr_in serv_adr, from_adr;
    Frame ackframe, recv_frame;
    int frame_id;
    int recv_result;
    struct timeval tv;

    if(argc!=3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }
    sock=socket(PF_INET, SOCK_DGRAM, 0);   
    if(sock==-1)
    {
        printf("error! failed to open the socket\n");
        exit(1);
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    adr_sz = sizeof(serv_adr);
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
    serv_adr.sin_port=htons(atoi(argv[2]));

    tv.tv_sec = 1;
    tv.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));

    frame_id = 0;
    while(1)
    {
        recv_result = recvfrom(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, &adr_sz);
        perror("error: ");
        printf("data %s\n", recv_frame.packet.data);
        printf("recv result %d\n", recv_result);
        printf("recv frame=%d, frame_kind = %d\n", recv_frame.sq_no, recv_frame.frame_kind);
        if(recv_result > 0 && recv_frame.frame_kind == 1 && recv_frame.sq_no==frame_id){
            printf("Frame %d received\n", recv_frame.sq_no);
            fprintf(outfile, "%s", recv_frame.packet.data);
            ackframe.frame_kind = 0;
            ackframe.ack = recv_frame.sq_no + 1;
            printf("Ack %d sent\n", ackframe.ack);
            sendto(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, adr_sz);


            break;
        }else{
            printf("Frame %d time expired\n", frame_id);
        }
    }   
    close(sock);
    fclose(outfile);
    return 0;
}

服务器需要 3 个参数:./server &lt;port&gt; &lt;test.txt&gt;

客户端还需要 3 个参数:./client &lt;ip&gt; &lt;port&gt;

执行了,但是客户端的recvfrom总是返回-1

我阅读了一些相同主题的问题,但无法从我的代码中找出错误。有没有办法用recvfromsendto 修复我的代码?还是我需要使用select 功能? (我只会与一台服务器和一台客户端通信。)

【问题讨论】:

  • 确实意识到fread()不会以空值终止它所读取的内容?
  • 哦,我在我的最新代码中修复了它,但没有修复此代码之一。但我不认为这是“资源暂时不可用”错误的原因。
  • 鉴于您 strcpy() 的某些内容可能不是以空值终止的,而之后您 memcpy() 的内容相同,我不倾向于为您调试此代码。
  • 如果像recvfrom 这样的系统调用返回-1,那么您可以(并且应该)检查errno 以查看问题所在。另外,errno 的值是 undefined 如果前一个函数实际上没有失败,永远不要检查 errno,除非前一个函数确实失败了。
  • 您收到该错误是因为您可能已将 a 设置为低超时。如果没有任何内容可接收,则recvfrom 函数将超时并返回该错误。至于为什么什么都没有收到是完全不同的故事,可能有一百个不同的原因,但在快速浏览您的代码后,您的程序似乎有点不对劲,我'将在答案中解释更多。

标签: c sockets udp recvfrom


【解决方案1】:

“客户端”和“服务器”程序包含一些可疑代码。首先让我们以“服务器”为例,它使用您尚未初始化clientaddr 调用sendto。谁知道您尝试将数据包发送到哪里。事实上,这会导致未定义的行为,因为结构的内容是不确定的

然后让我们使用客户端,您在其中调用recvfrom 的套接字上没有本地绑定。你传递给recvfrom的地址结构指针是由recvfrom函数填充的,但里面的数据并没有其他任何用途。

可能还有其他问题,但这两个比较突出。

【讨论】:

  • 我修好了。原因是初始化。 :)
  • @jungyh0218 请在我面临同样问题的答案中添加工作代码。我是初学者
  • @Iamlearning 如果您查看问题中的服务器代码,您会看到 OP 正在初始化结构 serveraddr,而不是结构 clientaddr。您必须使用要将数据包发送到的地址来初始化地址结构。
猜你喜欢
  • 1970-01-01
  • 2020-06-10
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 2018-02-08
  • 2017-03-26
  • 1970-01-01
相关资源
最近更新 更多