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
  • 相关阅读:
    Elasticsearch搜索引擎学习笔记(二)
    Elasticsearch搜索引擎学习笔记(一)
    Redis集群(cluster模式)搭建(三主三从)
    Redis主从、哨兵
    oracle 数据查询 返回树形结构的每一级的id
    oracle 数据库查询 COALESCE字符函数
    java 生成不重复的6位数字 +年月日
    oracle 数据库查询CLOB类型 报错 【ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB】
    oracle 数据表结构和数据 导入 导出
    sql 创建数据库表结构
  • 原文地址:https://www.cnblogs.com/rainbow1122/p/7875438.html
Copyright © 2011-2022 走看看