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
  • 相关阅读:
    LVS基于DR模式负载均衡的配置
    Linux源码安装mysql 5.6.12 (cmake编译)
    HOSt ip is not allowed to connect to this MySql server
    zoj 3229 Shoot the Bullet(无源汇上下界最大流)
    hdu 3987 Harry Potter and the Forbidden Forest 求割边最少的最小割
    poj 2391 Ombrophobic Bovines(最大流+floyd+二分)
    URAL 1430 Crime and Punishment
    hdu 2048 神、上帝以及老天爷(错排)
    hdu 3367 Pseudoforest(最大生成树)
    FOJ 1683 纪念SlingShot(矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/xumaomao/p/13162042.html
Copyright © 2011-2022 走看看