zoukankan      html  css  js  c++  java
  • Linux学习之socket编程(二)

    Linux学习之socket编程(二)

    1.C/S模型——UDP

    UDP处理模型

      由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实现。多保证通讯可靠性的机制需要在应用层实现。编译运行server,在两个终端里各开一个client与server交互,看看server是否具有并发服务的能力。用Ctrl+C关闭server,然后再运行server,看此时client还能否和server联系上。和前面TCP程序的运行结果相比较,体会无连接的含义。

    复制代码
    /* server.c */
    
    #include <stdio.h>
    #include <string.h>
    #include <netinet/in.h>
    #include "wrap.h"
    #define MAXLINE 80
    #define SERV_PORT 8000
    
    int main(void)
    {
        struct sockaddr_in servaddr, cliaddr;//用于IPv4的地址
        socklen_t cliaddr_len;
        int sockfd;//文件描述符
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];//16 Bytes
        int i, n;
        /*构造用于UDP通信的套接字*/
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);//
    
        bzero(&servaddr, sizeof(servaddr));//将地址清零
        //设置地址
        servaddr.sin_family = AF_INET;/*IPv4*/
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//网络字节数,本地任意IP
        servaddr.sin_port = htons(SERV_PORT);
        bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    
        printf("Accepting connections ...
    ");
        while (1) {
            cliaddr_len = sizeof(cliaddr);
    
            n = recvfrom(sockfd, buf, MAXLINE, 0, (struct sockaddr         *)&cliaddr, &cliaddr_len);
    
        if (n == -1)
            perr_exit("recvfrom error");
        printf("received from %s at PORT %d
    ",
    
            inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
            ntohs(cliaddr.sin_port));
    
        for (i = 0; i < n; i++)
            buf[i] = toupper(buf[i]);//小写转大写
        
         //发送数据
         n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
         
        if (n == -1)
            perr_exit("sendto error");
        }
    }        
    复制代码
    复制代码
    /* client.c */
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include "wrap.h"
    #define MAXLINE 80
    #define SERV_PORT 8000
    int main(int argc, char *argv[])
    {
        struct sockaddr_in servaddr;
        int sockfd, n;
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];
        socklen_t servaddr_len;
    
        sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    
        while(fgets(buf, MAXLINE, stdin) != NULL) {
    
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (n == -1)
             perr_exit ("sendto error");
    
        n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
    
        if (n == -1)
            perr_exit("recvfrom error");
       write(STDOUT_FILENO, buf, n);//写到屏幕上
        }
      close(sockfd);
        return 0;
    }        
    复制代码

    2.出错处理封装函数   上面的例子不仅功能简单,而且简单到几乎没有什么错误处理,我们知道,系统调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息。为使错误处理的代码不影响主程序的可读性,我们把与socket相关的一些系统函数加上错误处理代码包装成新的函数,做成一个模块wrap.c:

    复制代码
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/socket.h>
    void perr_exit(const char *s)
    {
        perror(s);
        exit(1);
    }
    
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
    {
        int n;
    again:
        if ( (n = accept(fd, sa, salenptr)) < 0) {
        if ((errno == ECONNABORTED) || (errno == EINTR))
    goto again;
        else
        perr_exit("accept error");
        }
        return n;
    }
    
    void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        if (bind(fd, sa, salen) < 0)
        perr_exit("bind error");
    }
    
    void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        if (connect(fd, sa, salen) < 0)
        perr_exit("connect error");
    }
    
    void Listen(int fd, int backlog)
    {
        if (listen(fd, backlog) < 0)
        perr_exit("listen error");
    }
    
    int Socket(int family, int type, int protocol)
    {
        int n;
        if ( (n = socket(family, type, protocol)) < 0)
        perr_exit("socket error");
        return n;
    }
    
    ssize_t Read(int fd, void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ( (n = read(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
    goto again;
        else
        return -1;
        }
        return n;
    }
    
    ssize_t Write(int fd, const void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ( (n = write(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
        goto again;
        else
        return -1;
       }
       return   n;
    }
    
    void Close(int fd)
    {
        if (close(fd) == -1)
        perr_exit("close error");
    }
    
    ssize_t Readn(int fd, void *vptr, size_t n)//指定读够n个字节返回
    {
        size_t nleft;
        ssize_t nread;
        char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
           if ( (nread = read(fd, ptr, nleft)) < 0) {
              if (errno == EINTR)
                    nread = 0;
              else
                    return -1;
        }   else if (nread == 0)
        break;
    
        nleft -= nread;
        ptr += nread;
    
        }
        return n - nleft;
    }
    
    ssize_t Writen(int fd, const void *vptr, size_t n)
    {
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
                if (nwritten < 0 && errno == EINTR)
                        nwritten = 0;
                else
                    return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
        }
        return n;
    }
    
    static ssize_t my_read(int fd, char *ptr)
    {
        static int read_cnt;
        static char *read_ptr;
        static char read_buf[100];
    
          if (read_cnt <= 0) {
    again:
        if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
        if (errno == EINTR)
        goto again;
        return -1;
        }
         else if (read_cnt == 0)
        return 0;
        read_ptr = read_buf;
        }
        read_cnt--;
        *ptr = *read_ptr++;
        return 1;
    }
    
    ssize_t Readline(int fd, void *vptr, size_t maxlen)//一次读一行
    {
        ssize_t n, rc;
        char c, *ptr;
    
        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
            if ( (rc = my_read(fd, &c)) == 1) {
                *ptr++ = c;
                  if (c == '
    ')
                        break;
               } else if (rc == 0) {
                *ptr = 0;
                  return n - 1;
                } else
                return -1;
        }
        *ptr = 0;
        return n;
    }   
    复制代码
    复制代码
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/socket.h>
    void perr_exit(const char *s)
    {
        perror(s);
        exit(1);
    }
    
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
    {
        int n;
    again:
        if ( (n = accept(fd, sa, salenptr)) < 0) {
        if ((errno == ECONNABORTED) || (errno == EINTR))
    goto again;
        else
        perr_exit("accept error");
        }
        return n;
    }
    
    void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        if (bind(fd, sa, salen) < 0)
        perr_exit("bind error");
    }
    
    void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        if (connect(fd, sa, salen) < 0)
        perr_exit("connect error");
    }
    
    void Listen(int fd, int backlog)
    {
        if (listen(fd, backlog) < 0)
        perr_exit("listen error");
    }
    
    int Socket(int family, int type, int protocol)
    {
        int n;
        if ( (n = socket(family, type, protocol)) < 0)
        perr_exit("socket error");
        return n;
    }
    
    ssize_t Read(int fd, void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ( (n = read(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
    goto again;
        else
        return -1;
        }
        return n;
    }
    
    ssize_t Write(int fd, const void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ( (n = write(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
        goto again;
        else
        return -1;
       }
       return   n;
    }
    
    void Close(int fd)
    {
        if (close(fd) == -1)
        perr_exit("close error");
    }
    
    ssize_t Readn(int fd, void *vptr, size_t n)//指定读够n个字节返回
    {
        size_t nleft;
        ssize_t nread;
        char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
           if ( (nread = read(fd, ptr, nleft)) < 0) {
              if (errno == EINTR)
                    nread = 0;
              else
                    return -1;
        }   else if (nread == 0)
        break;
    
        nleft -= nread;
        ptr += nread;
    
        }
        return n - nleft;
    }
    
    ssize_t Writen(int fd, const void *vptr, size_t n)
    {
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
                if (nwritten < 0 && errno == EINTR)
                        nwritten = 0;
                else
                    return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
        }
        return n;
    }
    
    static ssize_t my_read(int fd, char *ptr)
    {
        static int read_cnt;
        static char *read_ptr;
        static char read_buf[100];
    
          if (read_cnt <= 0) {
    again:
        if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
        if (errno == EINTR)
        goto again;
        return -1;
        }
         else if (read_cnt == 0)
        return 0;
        read_ptr = read_buf;
        }
        read_cnt--;
        *ptr = *read_ptr++;
        return 1;
    }
    
    ssize_t Readline(int fd, void *vptr, size_t maxlen)//一次读一行
    {
        ssize_t n, rc;
        char c, *ptr;
    
        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
            if ( (rc = my_read(fd, &c)) == 1) {
                *ptr++ = c;
                  if (c == '
    ')
                        break;
               } else if (rc == 0) {
                *ptr = 0;
                  return n - 1;
                } else
                return -1;
        }
        *ptr = 0;
        return n;
    }   
    复制代码
    复制代码
    /* wrap.h */
    #ifndef __WRAP_H_
    #define __WRAP_H_
    
    void perr_exit(const char *s);
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
    void Bind(int fd, const struct sockaddr *sa, socklen_t salen);
    void Connect(int fd, const struct sockaddr *sa, socklen_t salen);
    void Listen(int fd, int backlog);
    int Socket(int family, int type, int protocol);
    ssize_t Read(int fd, void *ptr, size_t nbytes);
    ssize_t Write(int fd, const void *ptr, size_t nbytes);
    void Close(int fd);
    ssize_t Readn(int fd, void *vptr, size_t n);
    ssize_t Writen(int fd, const void *vptr, size_t n);
    static ssize_t my_read(int fd, char *ptr);
    ssize_t Readline(int fd, void *vptr, size_t maxlen);
    
    #endif
    复制代码
    复制代码
    /* wrap.h */
    #ifndef __WRAP_H_
    #define __WRAP_H_
    
    void perr_exit(const char *s);
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
    void Bind(int fd, const struct sockaddr *sa, socklen_t salen);
    void Connect(int fd, const struct sockaddr *sa, socklen_t salen);
    void Listen(int fd, int backlog);
    int Socket(int family, int type, int protocol);
    ssize_t Read(int fd, void *ptr, size_t nbytes);
    ssize_t Write(int fd, const void *ptr, size_t nbytes);
    void Close(int fd);
    ssize_t Readn(int fd, void *vptr, size_t n);
    ssize_t Writen(int fd, const void *vptr, size_t n);
    static ssize_t my_read(int fd, char *ptr);
    ssize_t Readline(int fd, void *vptr, size_t maxlen);
    
    #endif
    复制代码
  • 相关阅读:
    微信小程序 单选按钮 最佳
    微信小程序 单选按钮的实现
    微信小程序 单选框实现
    Java Code To Create Pyramid and Pattern
    Java language
    npm Err! Unexpected end of JSON input while parsing near
    Node.js Express FrameWork Tutorial
    Higher-Order Function Examples
    Create First HTTP Web Server in Node.js: Complete Tutorial
    Node.js NPM Tutorial: Create, Publish, Extend & Manage
  • 原文地址:https://www.cnblogs.com/zzdbullet/p/9513626.html
Copyright © 2011-2022 走看看