V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
gzxultra
V2EX  ›  Linux

请教一个折腾好几天的问题, udp 收发小实验

  •  
  •   gzxultra · 2015-04-26 19:03:29 +08:00 · 2953 次点击
    这是一个创建于 3505 天前的主题,其中的信息可能已经有所发展或是发生改变。

    系统是Macintosh Yosemite,编译器gcc

    实验的基本内容是客户端发消息,服务器端回显,
    这里做在同一台电脑上用两个终端联系,

    • 第一次学这个,速度比较慢,弄了一晚上做出来了,回显一切正确。

    但是接下来麻烦来了

    • 第二天增加功能之前,测试了一下昨天的成果,结果试了多少遍,回显一直有问题。

    Alt text

    客户端显示莫名其妙的字符(好像是之前测试输入的。。跟本次输入完全没有关系)
    用很原始的调试方法发现,客户端显示的东西完全不是服务器端返回的(服务器端get sendline!这句话根本就不执行。。。)

    • 于是我用ubuntu虚拟机跑了一遍这个程序,第一遍okay,仅仅是重启了一下,又跟mac下一模一样了!!!
    • 哭死。。。。

    是我代码的问题还是电脑的问题
    能帮我解释一下为什么么?十分感谢!

    最后附代码

    /*
     * udpcli01.cpp
     *
     *  Created on: 2015年4月23日
     *      Author: gzxultra
     */
    
        #include        <netinet/in.h>
        #include        <errno.h>
        #include        <stdio.h>
        #include        <stdlib.h>
        #include        <sys/socket.h>
        #include        <string.h>
        #include        <arpa/inet.h>
        #define MAXLINE                  4096
        #define LISTENQ                  1024    /* 2nd argument to listen() */
        #define SERV_PORT                9877
        #define SA      struct sockaddr
    
    
        void dg_cli(FILE *, int, const SA *, socklen_t);
    
        int
        main(int argc, char **argv)
        {
            int sockfd;
            struct sockaddr_in servaddr;
    
            if (argc != 2) {
                printf("usage:udpcli01sigio <IPaddress>\n");
                exit(1);
            }
    
            bzero(&servaddr, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(SERV_PORT);
    
            inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    
            if((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) {
                printf("socket error.\n");
                exit(1);
            }
    
            dg_cli(stdin, sockfd, (SA *)&servaddr, sizeof(servaddr));
    
            exit(0);
        }
    
        void
        dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
        {
            int  n;
            char sendline[MAXLINE], recvline[MAXLINE + 1];
            //struct sockaddr_in from;
    
            while (fgets(sendline, MAXLINE,fp) != NULL) {
                sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
                n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
                recvline[n] = 0; /* null terminate */
                fputs(recvline, stdout);
                memset(sendline,0,sizeof(sendline));
                memset(recvline,0,sizeof(recvline));
            }
        }
    
    /*
     * udpserv01.cpp
     *
     *  Created on: 2015年4月23日
     *      Author: gzxultra
     */
    
    #include        <netinet/in.h>
    #include        <errno.h>
    #include        <stdio.h>
    #include        <stdlib.h>
    #include        <sys/socket.h>
    #include        <arpa/inet.h>
    #define MAXLINE                  4096
    #define LISTENQ                  1024    /* 2nd argument to listen() */
    #define SERV_PORT                9877
    #define SA      struct sockaddr
    #include    <string.h>
    
    
    static int sockfd;
    void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen, char *mesg);
    //void GetList(int sockfd, SA *pcliaddr, socklen_t clilen) ;
    
    int main(int argc, char ** argv) {
    
        struct sockaddr_in servaddr, cliaddr;
    
        //使用socket()函数生成套接字文件描述符
        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            printf("socket error.\n");
            exit(1);
        }
        //printf("I am not dead!\n");
    
        //设置服务器地址和侦听端口,初始化要绑定的网络地址结构
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;                      //地址类型为AF_INET
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);       //任意本地地址
        servaddr.sin_port = htons(SERV_PORT);               //服务器端口
    
        //绑定侦听端口
        bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
    
    /*
        char instruction[3][10] = {
            "getlist\0",
            "download\0",
            "upload\0"
        };
    */
        int op = 0;
        int i = 0,j = 0;
        int n = 0;
        char mesg[MAXLINE];
        socklen_t len = sizeof(cliaddr);
        printf("running here!\n");
        while(1){
            //len = clilen;
    
            //recvfrom接收客户端的网络数据
            //printf("running here2!\n");
            n = recvfrom(sockfd, mesg, MAXLINE, 0, (SA *) &cliaddr,  &len);
            printf("get sendline!\n");
    
            dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr), mesg);
            printf("echo done!\n");
        }
    }
    
    void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen, char *mesg) {
    
        sendto(sockfd, mesg, sizeof(mesg), 0, pcliaddr, clilen);
    
    }
    
    6 条回复    2015-04-27 16:47:29 +08:00
    xenme
        1
    xenme  
       2015-04-26 19:40:35 +08:00
    recvfrom没收到消息,就会一直阻塞
    所以,就一直卡在那里了
    gzxultra
        2
    gzxultra  
    OP
       2015-04-26 19:45:36 +08:00
    @xenme
    就是想知道为啥recvfrom没收到消息
    网络不好?系统问题还是代码错了?
    感谢!
    zhjits
        3
    zhjits  
       2015-04-26 19:49:38 +08:00
    @gzxultra 你用 Wireshark 抓包看看
    kkfnui
        4
    kkfnui  
       2015-04-26 21:11:01 +08:00
    没有收到数据的原因:
    1. 运行client程序,传入的ip地址错误的,我第一遍输入127.0.0.1 确实出现了楼主说的情况
    2. 系统有防火墙,禁止server程序传入数据

    乱码的原因,是你接收数据的缓冲区没有初始化了。

    变量定义的时候初始化是个好习惯。
    catro
        5
    catro  
       2015-04-27 12:35:23 +08:00
    关于显示莫名字符串的问题
    1. 字符串取长度用strlen,代码里好多用了sizeof。
    2. 客户端传给服务端的字符串不带0,服务端取长度前要加0。

    不回显的问题参考3楼用Wireshark分析。
    gzxultra
        6
    gzxultra  
    OP
       2015-04-27 16:47:29 +08:00
    @catro

    首先感谢热心解答,莫名字符串已修改

    关于无法recvfrom的问题也已经发现原因和解决方法
    习惯sublime先手编译一下,command+b 实际上运行了程序(开了一个服务器进程)
    命令行执行开了一个服务器进程,
    因为有两个服务器端口,client端无法正确发送!!!
    折磨我几天了,再次感谢!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2674 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 05:09 · PVG 13:09 · LAX 21:09 · JFK 00:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.