UNIX网络编程笔记 第八章 基本UDP套接字编程

recvfrom和sendto函数:
#include <sys/socket.h>

ssize_t recvfrom(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen);

ssize_t sendto(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);

//若成功则返回读或写的字节数,若出错返回-1

//tcp套接字read时返回0代表连接已关闭;udp套接字则不然,recvfrom返回0是一种正常状态
udp的异步错误:

如果udp客户端向一个服务进程未启动的服务端发送数据,虽然网络会返回一个端口不可达错误,但是客户端进程的sendto并不会返回错误,而是返回成功(因为udp输出操作成功返回,仅仅代表在接口输出队列中具有存放该IP数据报的空间,但是ICMP错误要更晚一些时候才返回,这就是称其为异步的原因)。

一个几本原则是:对于一个udp套接字,由它引发的异步错误并不返回给它,除非它已连接(调用connect函数)

示例代码: :
//server.c
#include "common.h"
#include <poll.h>
#include <limits.h>


int main(int argc, char **agrv){

    int tcpsockfd,udpsockfd,tcpclientfd;
    struct sockaddr_in serveraddr,clientaddr;
    socklen_t addrlen = sizeof(clientaddr);

    bzero(&serveraddr,sizeof(serveraddr));
    bzero(&clientaddr,sizeof(clientaddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(45000);
    inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);

    tcpsockfd = socket(AF_INET,SOCK_STREAM,0);
    bind(tcpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    listen(tcpsockfd,20);

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(45000);
    inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);

    udpsockfd = socket(AF_INET,SOCK_DGRAM,0);
    bind(udpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));

    struct pollfd allsockets[OPEN_MAX];
    for(int i = 0; i < OPEN_MAX; i ++){
        allsockets[i].fd = -1;
    }

    allsockets[0].fd = tcpsockfd;
    allsockets[0].events = POLLRDNORM;

    allsockets[1].fd = udpsockfd;
    allsockets[1].events = POLLRDNORM;

    int maxi = 1;
    int i;
    char buf[800];

    while(1){

        int newMaxi = 0;
        for(int i = 0; i <= maxi; i++){
            if(allsockets[i].fd != -1)
                newMaxi = i;
        }
        maxi = newMaxi;

        int nready = poll(allsockets,maxi+1,-1);

        if(allsockets[0].revents & (POLLRDNORM | POLLERR)){
            tcpclientfd = accept(tcpsockfd,(struct sockaddr*)&clientaddr,&addrlen);
            if(tcpclientfd < 0){
                if(errno == EINTR){
                    ;
                }else{
                    puts("accept error");
                }
            }else{
                for(i = 2; i < OPEN_MAX; i++){
                    if(allsockets[i].fd == -1){
                        allsockets[i].fd = tcpclientfd;
                        allsockets[i].events = POLLRDNORM;
                        maxi = MAX(maxi,i);
                        break;
                    }
                }
            }
            nready--;
        }

        if(allsockets[1].revents & POLLRDNORM){
            int readnum = recvfrom(udpsockfd,buf,sizeof(buf),0,(struct sockaddr*)&clientaddr,&addrlen);
            printf("read %d bytes from udp client\n",readnum);
            if(readnum < 0){
                close(udpsockfd);
                puts("read from udpclient error");
            }else{
                buf[readnum] = 0;
                printf("%s",buf);
                int sendnum = sendto(udpsockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,addrlen);
                if(sendnum < 0) err_sys("udp send error");
                else
                    printf("%d bytes sent\n",readnum);
            }

            nready--;
        }

        for(i = 2; i <= maxi; i++){
            int tcpclientfd = allsockets[i].fd;
            if(tcpclientfd != -1 && (allsockets[i].revents & POLLRDNORM)){
                int readnum = read(tcpclientfd,buf,sizeof(buf));
                buf[readnum] = 0;
                if(readnum < 0){
                    if(errno == EINTR){
                        continue;
                    }else{
                        close(tcpclientfd);
                        allsockets[i].fd = -1;
                        puts("rad error");
                    }
                }else if (readnum == 0){
                    close(tcpclientfd);
                    allsockets[i].fd = -1;
                    puts("tcp client close socket");
                }else{
                    printf("%s",buf);
                    int writenum = write(tcpclientfd,buf,readnum);
                    if(writenum < 0){
                        err_sys("write error");
                    }else{
                        printf("%d bytes sent\n",readnum);
                    }
                }
                if(--nready <= 0)
                    break;
            }
        }

    }

}
//client.c
#include "common.h"

int main(int argc, char **argv){


    int sockfd;
    struct sockaddr_in serveraddr,clientaddr;
    char buf[100];

    bzero(&serveraddr,sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);
        serveraddr.sin_port = htons(45000);

    bzero(&clientaddr,sizeof(clientaddr));

        sockfd = socket(AF_INET,SOCK_DGRAM,0);

    int rtn = connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    if(rtn != 0){
        err_sys("connect error");

    }   

    fd_set readset;
    FD_ZERO(&readset);
    FD_SET(sockfd,&readset);
    int sockStdin = fileno(stdin);
    FD_SET(fileno(stdin),&readset);

    int stdineof = 0;

    while (1) {
        FD_SET(sockfd,&readset);
        int maxfd = sockfd;
        if(stdineof == 0) {
            FD_SET(sockStdin,&readset);
            maxfd = MAX(sockfd,fileno(stdin));  
        }   
        int nReady = select(maxfd + 1,&readset,NULL,NULL,NULL);
        printf("nReady = %d\n",nReady);
        socklen_t addrlen = sizeof(clientaddr);
        if(nReady > 0){
            if(FD_ISSET(sockStdin,&readset)){
                puts("read from stdin");
                int readNum = read(sockStdin,buf,sizeof(buf));
                if(readNum == 0){
                    puts("eof, close socket");
                    shutdown(sockfd,1);
                    FD_CLR(sockStdin,&readset);
                    stdineof = 1;
                    continue;

                }
                //int sendnum = sendto(sockfd,buf,readNum,0,(struct sockaddr*)&serveraddr,addrlen);
                int sendnum = write(sockfd,buf,readNum);
                if(sendnum < 0) err_sys("sendto error");
                printf("%d bytes sent\n",sendnum);
            }

            if(FD_ISSET(sockfd,&readset)){
                puts("read from server");
                //int readNum = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serveraddr,&addrlen);
                int readNum = read(sockfd,buf,sizeof(buf));
                if(readNum == 0){
                    if(stdineof == 1) {
                        puts("server close socket");
                        return 0;
                    }
                    else err_sys("client read error");
                }
                write(fileno(stdout),buf,readNum);

            }

        }

    }       


    return 0;


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值