zoukankan      html  css  js  c++  java
  • socket编程实例-TCP

    第一版:实现简单功能

    客户端从标准输入读入字符串传给服务端,服务端把字符串中的小写字母转化为大写字母传回客户端

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <string.h>
    
    #define SERV_IP "127.0.0.1"
    #define SERV_PORT 6666
    
    int main()
    {
            int cfd;
            struct sockaddr_in serv_addr;
            socklen_t serv_addr_len;
            char buf[BUFSIZ];
            int n;
    
            cfd = socket(AF_INET, SOCK_STREAM, 0);
    
            memset(&serv_addr, 0, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_port = htons(SERV_PORT);
            //serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
    
            //客户端可以不用bind()绑定ip和端口号,操作系会默认分配
    
            connect(cfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    
            while(1)
            {
                    fgets(buf, sizeof(buf), stdin);
                    write(cfd, buf, strlen(buf));
                    n = read(cfd, buf, sizeof(buf));
                    write(STDOUT_FILENO, buf, n);
            }
    
            close(cfd);
    
            return 0;
    }
    client.c
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    
    #define SERV_PORT 6666
    
    int main()
    {
            int sfd, cfd;
            struct sockaddr_in serv_addr, clie_addr;
            socklen_t clie_addr_len;
            char buf[BUFSIZ];
            int n, i;
    
            sfd = socket(AF_INET, SOCK_STREAM, 0);
    
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_port = htons(SERV_PORT);
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
            bind(sfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    
            listen(sfd, 128);
    
            clie_addr_len = sizeof(clie_addr);
            cfd = accept(sfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
    
            while(1)
            {
                    n = read(cfd, buf, sizeof(buf));
                    for(i=0; i<n; i++)
                    {
                            buf[i] = toupper(buf[i]);
                    }
                    write(cfd, buf, n);
            }
    
            close(sfd);
            close(cfd);
    
            return 0;
    }
    server.c

    第二版:加入错误封装

    上面没有对错误进行处理,我们知道,系统调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息。为使错误处理的代码不影响主程序的可读性,我们把与socket相关的一些系统函数加上错误处理代码包装成新的函数(新函数和原函数调用的区别仅仅在于新函数名首字母大写了),做成一个模块wrap.c,这样在调用socket函数时,调用我们封装了错误处理的函数就可以了。

    #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;
    }
    int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        int n;
        if ((n = bind(fd, sa, salen)) < 0)
            perr_exit("bind error");
        return n;
    }
    int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        int n;
        if ((n = connect(fd, sa, salen)) < 0)
            perr_exit("connect error");
        return n;
    }
    int Listen(int fd, int backlog)
    {
        int n;
        if ((n = listen(fd, backlog)) < 0)
            perr_exit("listen error");
        return n;
    }
    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;
    }
    int Close(int fd)
    {
        int n;
        if ((n = close(fd)) == -1)
            perr_exit("close error");
        return n;
    }
    ssize_t Readn(int fd, void *vptr, size_t 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.c
    #ifndef __WRAP_H_
    #define __WRAP_H_
    void perr_exit(const char *s);
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
    int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
    int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
    int 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);
    int Close(int fd);
    ssize_t Readn(int fd, void *vptr, size_t n);
    ssize_t Writen(int fd, const void *vptr, size_t n);
    ssize_t my_read(int fd, char *ptr);
    ssize_t Readline(int fd, void *vptr, size_t maxlen);
    #endif
    wrap.h

    第三版:使用多进程技术在服务端实现高并发

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <strings.h>
    #include <sys/wait.h>
    
    #include "wrap.h"
    
    #define SERV_PORT 6666
    
    void wait_child(int signo)
    {
            while(waitpid(0, NULL, WNOHANG) > 0);
            return ;
    }
    
    int main()
    {
            pid_t pid;
            int sfd, cfd;
            struct sockaddr_in serv_addr, clie_addr;
            socklen_t clie_addr_len;
            char buf[BUFSIZ], clie_IP[BUFSIZ];
            int n, i;
    
            sfd = Socket(AF_INET, SOCK_STREAM, 0);
    
            bzero(&serv_addr, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_port = htons(SERV_PORT);
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
            Bind(sfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    
            Listen(sfd, 128);
    
            while(1)
            {
                    clie_addr_len = sizeof(clie_addr);
                    cfd = Accept(sfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
                    printf("client IP: %s, port: %d
    ", inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), ntohs(clie_addr.sin_port));
    
                    pid = fork();
                    if(pid < 0)
                    {
                            perror("fork error");
                            exit(1);
                    }
                    else if(pid == 0)
                    {
                            close(sfd);
                            break;
                    }
                    else
                    {
                            close(cfd);
                            signal(SIGCHLD, wait_child);
                    }
            }
    
            if(pid == 0)
            {
                    while(1)
                    {
                            n = Read(cfd, buf, sizeof(buf));
                            if(n == 0)
                            {
                                    close(cfd);
                                    return 0;
                            }
                            else if(n == -1)
                            {
                                    perror("read error");
                                    exit(1);
                            }
                            else
                            {
                                    for(i=0; i<n; i++)
                                    {
                                            buf[i] = toupper(buf[i]);
                                    }
                                    write(cfd, buf, n);
                                    write(STDOUT_FILENO, buf, n);
                            }
                    }
            }
    
            return 0;
    }
    server.c

    第四版:使用多线程技术在服务端实现高并发

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <strings.h>
    #include <sys/wait.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <string.h>
    
    #include "wrap.h"
    
    #define SERV_PORT 6666
    #define MAXLINE 8192
    
    struct s_info{
            struct sockaddr_in cliaddr;
            int connfd;
    };
    
    void* do_work(void *arg)
    {
            int n,i;
            struct s_info *ts = (struct s_info*)arg;
            char buf[MAXLINE];
            char str[INET_ADDRSTRLEN];
    
            while(1){
                    n = Read(ts->connfd, buf, MAXLINE);
                    if(n == 0){
                            printf("the client %d closed...
    ", ts->connfd);
                            break;
                    }
                    printf("received from %s at PORT %d
    ", inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)), ntohs((*ts).cliaddr.sin_port));
                    for(i=0; i<n; i++){
                            buf[i] = toupper(buf[i]);
                    }
                    write(ts->connfd, buf, n);
                    write(STDOUT_FILENO, buf, n);
            }
            Close(ts->connfd);
    
            return (void *)0;
    }
    
    int main()
    {
            int sfd, cfd;
            struct sockaddr_in serv_addr, clie_addr;
            socklen_t clie_addr_len;
            struct s_info ts[256];
            pthread_t tid;
            int i = 0;
    
            sfd = Socket(AF_INET, SOCK_STREAM, 0);
    
            bzero(&serv_addr, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_port = htons(SERV_PORT);
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
            Bind(sfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    
            Listen(sfd, 128);
    
            while(1)
            {
                    clie_addr_len = sizeof(clie_addr);
                    cfd = Accept(sfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
                    ts[i].cliaddr = clie_addr;
                    ts[i].connfd = cfd;
    
                    pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
                    pthread_detach(tid);
                    i++;
            }
    
            return 0;
    }
    server.c
  • 相关阅读:
    Mysql初始化root密码和允许远程访问
    windows下nodejs express安装及入门网站,视频资料,开源项目介绍
    python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码
    python3.4学习笔记(二十五) Python 调用mysql redis实例代码
    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
    python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码
    python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字
    python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法
    python3.4学习笔记(二十) python strip()函数 去空格 函数的用法
    python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法
  • 原文地址:https://www.cnblogs.com/xumaomao/p/13162042.html
Copyright © 2011-2022 走看看