美文网首页
网络编程

网络编程

作者: 酸菜牛肉 | 来源:发表于2017-01-21 21:07 被阅读16次

    select函数实现多任务的用户操作,回弹信息。。

    // 回射服务器客户端
    // 从键盘读入数据,将读入的数据发送给服务器,然后接收服务器回弹的数据
    // 服务器的IP和端口从服务器读入
    // ./echo_client <server_ip> <server_port>
    
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define N 200
    
    int main(int argc, char *argv[])
    {
        if(argc != 3)
        {
            printf("usage : %s <server_ip> <server_port>\n", argv[0]);
            return 1;
        }
    
        char buf[N] = {'\0'};
        int n = 0;
        
        // 1.socket
        int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
        
        // 2.connect
        struct sockaddr_in serveraddr;
        
        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
        serveraddr.sin_port = htons(atoi(argv[2]));
        if(connect(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
        {
            perror("connect failed");
            return 1;
        }
        
        // 3.read/write
        // 循环从键盘读入数据,发送给服务器端,当输入.exit时,客户端退出
        while(1)
        {
            // 3.1从键盘读入数据
            write(STDOUT_FILENO, ">", 1);
            n = read(STDIN_FILENO, buf, N);
            
            // 3.2将读入的数据发送给服务器
            // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
            // 参数:
            // sockfd   使用sockfd所关联的套接字发送数据
            // buf      待发送数据的起始地址
            // len      待发送数据的字节长度
            // flags    发送方式
            // 返回值:实际发送成功的字节数
            send(sock_fd, buf, n, 0);
            
            // 当从键盘读入的数据为.exit时,客户端退出
            if(strncmp(buf, ".exit", 5) == 0)
                break;
    
            // 3.3接收从服务器回弹的数据病打印
            // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
            // 参数:
            // sockfd   从sockfd所关联的套接字中接收数据
            // buf      存放接收数据的空间的起始地址
            // len      存放空间的最大字节数
            // flags    接收方式
            n = recv(sock_fd, buf, N, 0);
            printf("echo from server : \n");
            write(STDOUT_FILENO, buf, n);
        }
        
        printf("client exit, bye!!!\n");
        
        // close
        close(sock_fd);
        return 0;
    }
    
    
    // void FD_CLR(int fd, fd_set *set);
    // 将参数fd所关联的文件描述符从参数set集合中清楚
    
    //int  FD_ISSET(int fd, fd_set *set);
    // 判断fd文件描述符是否在参数set集合中
    
    //void FD_SET(int fd, fd_set *set);
    // 将参数fd文件描述符加入到set集合中
    
    //void FD_ZERO(fd_set *set);
    // 清空集合set
    
    // int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    // 参数:
    // nfds :   三个集合中最大文件描述符+1
    // readfds :    读集合
    // writefds :   写集合
    // exceptfds :  异常集合
    // timeout :    超时时间
    
    // 使用select函数为TPC服务器添加主动退出功能
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <sys/time.h>
    #include <sys/select.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define N 100
    
    int main(int arc, char *argv[])
    {
        int sock_fd = 0;
        struct sockaddr_in serveraddr;
        struct sockaddr_in clientaddr;
        socklen_t len = 0;
        int conn_fd = 0;
        char buf[N] = {'\0'};
        int i = 0;
        int j = 0;
    
        // 1.socket     SOCK_STREAM
        sock_fd = socket(AF_INET, SOCK_STREAM, 0);
        
        // 2.bind
        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr("10.211.55.3");
        //serveraddr.sin_addr.s_addr = INADDR_ANY;
        serveraddr.sin_port = htons(8888);
        if(bind(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
        {
            perror("bind failed");
            return 1;
        }
        
        // 3.listen
        listen(sock_fd, 15);
        
        // 使用select函数同时监控标准输入文件和监听套接字的使用
        // 1)创建文件描述符集合
        fd_set readfds;
        fd_set tmpfds;
        int max_fd = 0;
        FD_ZERO(&readfds);
        
        // 2)将需要被监控的描述符添加到集合中
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(sock_fd, &readfds);
        max_fd = STDIN_FILENO>sock_fd?STDIN_FILENO:sock_fd;
        
        // 3)调用select函数筛选数据就绪的文件描述符
        while(1) 
        {
            tmpfds = readfds;
            // select函数的功能为将提供的集合中数据就绪的留下
            select(max_fd+1, &tmpfds, NULL, NULL, NULL);
            
            // 4)根据文件描述符是否在筛选后的集合中,来执行相应操作
            for(i = 0; i < max_fd+1; i++)
            {
                if(!FD_ISSET(i, &tmpfds))
                    continue;
                    
                if(i == STDIN_FILENO)
                {
                    // 标准输入文件就绪,处理数据读入  
                    fgets(buf, N, stdin);
                    if(strncmp(buf, ".exit", 5) == 0)
                        exit(0);
                }else if(i == sock_fd)
                {
                    // 监听套接字就绪,处理连接请求   
                    // 4.recv data/send data
                    memset(&clientaddr, 0, sizeof(clientaddr));
                    len = sizeof(clientaddr);
                    conn_fd = accept(sock_fd, (struct sockaddr *)&clientaddr, &len);
                    printf("conection with %s : %d\n",
                        inet_ntoa(clientaddr.sin_addr),
                        ntohs(clientaddr.sin_port));
        
                    // 将新建的连接套接字加入到readfds中
                    FD_SET(conn_fd, &readfds);
                    // 更新max_fd
                    if(conn_fd > max_fd)
                        max_fd = conn_fd;
                }
                else
                {
                    // 某一个了连接套接字就绪
                    // 接收客户端发送来的数据并回弹
                    recv(i, buf, N, 0);
                    
                    if(strncmp(buf, ".exit", 5) == 0)
                    {
                        // 将该连接套接字从readfds中清除
                        FD_CLR(i, &readfds);
                        // 如果需要则更新max_fd
                        if(i == max_fd)
                        {
                            // 注意:以下写法为C99标准支持
                            for(j = max_fd-1; j >= 0; j--)
                            {
                                if(FD_ISSET(j, &readfds))
                                    break;
                            }
                            max_fd = j;
                        }
                        // 关闭该连接
                        close(i);
                    }
                    else
                    {
                        send(i, buf, N, 0);
                    }
                }
            }
        }
        
        // 6.close
        close(sock_fd);
    
        return 0;
    }
    

    1.会使用哪些容器,
    2.数据库的数据是怎么传输的
    3.TCP和UDP的用处,具体怎么实现的
    4.信号
    5.链表
    6.面向对象
    7.设计模式
    8.你是做底层还是上层的
    9.你是做前端还是后端的,

    10.进程间通信方式,至少5种?
    11.实时系统有哪几种特性?
    12.简述一下三次握手
    13.进程间通信同步方式有哪些
    14.tcp/ip有几层?具体讲讲数据链路层?
    15.tcp/ip有几次握手,几次断开?具体握手过程?
    16.进通信有哪些?(具体讲讲信号量,具体讲讲消息队列),
    17.客户端和服务器用的是进程还是线程,为什么?
    18.多人聊天客户端直接断开了,服务器怎么解决?
    19.多人聊天的时候有没有考虑互斥等问题?

    20.tcp和udp有什么区别
    21,学过数据结构吗?
    22,TCP四次分手中,主动关闭方最后为什么要等待MSL之后才关闭连接?
    23,数据库和服务器的连接方式
    24.聊天系统太简单了,一般公司不开发的,你们是要卖吗?
    25.说说TCP、UDP的区别?
    26.写一下并发性TCP伪代码?
    27.进程间的通信方式有哪些?区别?
    28.写一个服务器端的代码?(简单的)
    29.写一个客户端的代码?
    30.Socket模型有select ,iocp,epoll三种,试着阐述原理,比较差异。

    技术题:
    1.面试他们会把你简历上你列出来的专业技能都会对你提问
    2.基类,子类析构顺序
    3.网络模型

    4.vector和list区别
    5.malloc和new区别
    6.继承和组合区别
    7.select里的enjoy
    8.进程和线程的区别
    9.你对面向对象有多少了解

    相关文章

      网友评论

          本文标题:网络编程

          本文链接:https://www.haomeiwen.com/subject/tjssbttx.html