码迷,mamicode.com
首页 > 其他好文 > 详细

socket编程---UDP

时间:2018-11-13 22:41:12      阅读:262      评论:0      收藏:0      [点我收藏+]

标签:异步   target   out   遇到   指定   通过   emc   set   efi   

头文件

#include <sys/types.h>
#include <sys/socket.h>

函数原型

int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);

int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);

编写程序的过程遇到的问题及解决办法都在代码中说明

server

/*************************************************************************
    > File Name: server.c
    > Author: Chen
    > Mail: 971859774@qq.com 
    > Created Time: 2018年11月12日 星期一 21时30分34秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877

void dg_ser(int sockfd,struct sockaddr * cliaddr,socklen_t clilen)
{
    char msg[MAXLINE];
    memset(msg,sizeof(msg),0);
    int index=0;
    while(1)
    {
        socklen_t len=clilen;

        int n=recvfrom(sockfd,msg,MAXLINE,0,cliaddr,&len);
        char m[len];
        printf("server receive from %s, message: %s",inet_ntop(AF_INET,cliaddr,m,len),msg);
        sendto(sockfd,msg,n,0,cliaddr,len);
    }
    return;
}

int main(int argc,char **argv)
{
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);

    struct sockaddr_in servaddr,cliaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_port=htons(SERV_PORT);
    servaddr.sin_family=AF_INET;
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

    bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

    dg_ser(sockfd,(struct sockaddr *)&cliaddr,sizeof(cliaddr));

    return 0;
}

调用connect的client

/*************************************************************************
    > File Name: client.c
    > Author: Chen
    > Mail: 971859774@qq.com 
    > Created Time: 2018年11月12日 星期一 20时47分06秒
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877

void dg_cli(int sockfd,const struct sockaddr* servaddr,socklen_t servlen)
{
    char sendline[MAXLINE],recvline[MAXLINE+1];

    //调用connect的udp套接字
    int res=connect(sockfd,(struct sockaddr *)servaddr,servlen);
    if(res<0)
    {
        fprintf(stderr,"connect error\n");
        exit(0);
    }
    
    /*利用connect确定外出接口,因为connect udp套接字的时候,内核自动选
     *(假设未显示调用bind),本地ip地址通过为目的ip地址搜索路由表得到的
     *外出借口,然后选用该接口的主ip地址而选定
     */
    struct sockaddr_in cliaddr;
    socklen_t len=sizeof(cliaddr);
    getsockname(sockfd,(struct sockaddr *)&cliaddr,&len);
    char m[len];
    printf("local address: %s\n",inet_ntop(AF_INET,(struct sockaddr *)&cliaddr,m,len));

    while(fgets(sendline,MAXLINE,stdin)!=NULL)
    {
        /*
         * 如果此时服务器未启动,客户将永远阻塞在recvfrom中。
         * 愿意:在客户像服务器发送udp数据报之前,先进行一次arp的请求答应
         * 交换,这个 请求交换放在tcpdump中输出中,服务器相应一个端口不可
         * 达错误,这也成为异步错误,该错误有sendto引起,但sendto却成功返回
         * ,udp输出操作成功返回仅仅表示接口接口队列中具有存放形成的ip数据
         * 报的空间,对于udp套接字,由它引发的错误却不返回给他
         */
        
        size_t fw=write(sockfd,sendline,strlen(sendline));
        if(fw<0)
        {
            fprintf(stderr,"write error\n");
            exit(0);
        }

        size_t n=read(sockfd,recvline,MAXLINE);
        char *msg=strerror(errno);
        if(errno==111)
        {
            fprintf(stderr,"%s\n",msg);
            exit(1);
        }

        if(n<0)
        {
            fprintf(stderr,"read error\n");
        }

        recvline[n]=\0;
        fputs(recvline,stdout);

        bzero(sendline,MAXLINE);
        bzero(recvline,MAXLINE);
    }
    return;
}

int main(int argv,char **argc)
{
    if(argv!=2)
        err_quit("please input address");

    /*
     * 客户必须给出服务器的ip和端口号,一般来说客户的端口号和ip由内核自动
     * 选则,临时端口号是在第一次sendto时一次性选定的不能改,ip可以变动。
     * 也可用bind指定
     */
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(SERV_PORT);
    inet_pton(AF_INET,argc[1],&servaddr.sin_addr);

    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    
    dg_cli(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    return 0;
}

没有调用connect的client

/*************************************************************************
    > File Name: client.c
    > Author: Chen
    > Mail: 971859774@qq.com 
    > Created Time: 2018年11月12日 星期一 20时47分06秒
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877

void dg_cli(int sockfd,const struct sockaddr* servaddr,socklen_t servlen)
{
    char sendline[MAXLINE],recvline[MAXLINE];

    while(fgets(sendline,MAXLINE,stdin)!=NULL)
    {
        /*
         * 如果此时服务器未启动,客户将永远阻塞在recvfrom中。
         * 愿意:在客户像服务器发送udp数据报之前,先进行一次arp的请求答应
         * 交换,这个 请求交换放在tcpdump中输出中,服务器相应一个端口不可
         * 达错误,这也成为异步错误,该错误有sendto引起,但sendto却成功返回
         * ,udp输出操作成功返回仅仅表示接口接口队列中具有存放形成的ip数据
         * 报的空间,对于udp套接字,由它引发的错误却不返回给他
         */
        sendto(sockfd,sendline,strlen(sendline),0,servaddr,servlen);
        
        //接受套接字服务器返回来的套接字,来判断返回的是不是本台主机向服务器所发的消息
        struct sockaddr *rep_ser=malloc(servlen);
        socklen_t len=servlen;
        int n=recvfrom(sockfd,recvline,MAXLINE,0,rep_ser,&len);

        char msg[len];
        if(len!=servlen||memcmp(servaddr,rep_ser,len)!=0)
        {
            printf("reply from %s (ignore)\n",inet_ntop(AF_INET,rep_ser,msg,len));
            continue;
        }
        
        recvline[n]=\0;

        fputs(recvline,stdout);
    }
    return;
}

int main(int argv,char **argc)
{
    if(argv!=2)
        err_quit("please input address");

    /*
     * 客户必须给出服务器的ip和端口号,一般来说客户的端口号和ip由内核自动
     * 选则,临时端口号是在第一次sendto时一次性选定的不能改,ip可以变动。
     * 也可用bind指定
     */
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(SERV_PORT);
    inet_pton(AF_INET,argc[1],&servaddr.sin_addr);

    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    
    dg_cli(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    return 0;
}

udp的connect:https://www.cnblogs.com/tianzeng/p/9925594.html

socket编程---UDP

标签:异步   target   out   遇到   指定   通过   emc   set   efi   

原文地址:https://www.cnblogs.com/tianzeng/p/9955184.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!