Linux Network Programming (3)

1. recv and send function

2. tcp state transition

3. 2msl long wait

TIME_WAIT state will last for about a minute before it closed.

4. Close half

 

               

You can copy a file descriptor dup2 function, after fd sfd and they all point to the same socket. If a file descriptor close off function, then the other can also read and write file descriptors socket. So it is still good with a shutdown function, this function can be turned off on the socket specified operating authority, that all point to the socket file descriptor will lose authority to operate specified.

5. netstat command

Results of the:

First start the server end, and then view with this command. Then start a client-side, view it with this command.

NOTE: If the client terminal is connected to a disconnection, in one minute using this command to display find that the client-side state to TIME_WAIT.

6. port multiplexing is provided

Usage: Before bind, port multiplexing is provided. In this way the server off and then immediately open the port occupied by the error will not show up.

7. IO multiplexer

  

8. kernel is how to achieve roughly the IO adapter

9. select the parameters and return values

                                        

Note:. 1 writefds exceptfds general and pass NULL, set only readfds. 1024 bits and is recorded in nature. 2. The function return value is a few fd changed. 3. If the timeout parameter does not pass NULL, then only when the blocking time to set up, the function does not return.

10. select the work process

NOTE: After select the function returns, reads may be altered: fd changes a value of 1, fd not changed its value is 0. We need only to traverse it reads fd know what has changed.

11. select pseudocode

12. select code implementation

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>


int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
        printf("eg: ./a.out port\n");
        exit(1);
    }
    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    int port = atoi(argv[1]);

    // 创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in 
    memset(&serv_addr, 0, serv_len);
    serv_addr.sin_family = AF_INET;                   // 地址族 
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口 
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    struct sockaddr_in client_addr;
    socklen_t cli_len = sizeof(client_addr);

    // 最大的文件描述符
    int maxfd = lfd;
    // 文件描述符读集合
    fd_set reads, temp;
    // init
    FD_ZERO(&reads);
    FD_SET(lfd, &reads);

    while(1)
    {
        // 委托内核做IO检测
        temp = reads;
        int ret = select(maxfd+1, &temp, NULL, NULL, NULL);
        if(ret == -1)
        {
            perror("select error");
            exit(1);
        }
        // 客户端发起了新的连接
        if(FD_ISSET(lfd, &temp))
        {
            // 接受连接请求 - accept不阻塞
            int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
            if(cfd == -1)
            {
                perror("accept error");
                exit(1);
            }
            char ip[64];
            printf("new client IP: %s, Port: %d\n", 
                   inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),
                   ntohs(client_addr.sin_port));
            // 将cfd加入到待检测的读集合中 - 下一次就可以检测到了
            FD_SET(cfd, &reads);
            // 更新最大的文件描述符
            maxfd = maxfd < cfd ? cfd : maxfd;
        }
        // 已经连接的客户端有数据到达
        for(int i=lfd+1; i<=maxfd; ++i)
        {
            if(FD_ISSET(i, &temp))
            {
                char buf[1024] = {0};
                int len = recv(i, buf, sizeof(buf), 0);
                if(len == -1)
                {
                    perror("recv error");
                    exit(1);
                }
                else if(len == 0)
                {
                    printf("客户端已经断开了连接\n");
                    close(i);
                    // 从读集合中删除
                    FD_CLR(i, &reads);
                }
                else
                {
                    printf("recv buf: %s\n", buf);
                    send(i, buf, strlen(buf)+1, 0);
                }
            }
        }
    }

    close(lfd);
    return 0;
}

Results of the:

 

13. select function advantages and disadvantages

14. poll function Introduction

15. poll codes achieve IO adapter

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <poll.h>

#define SERV_PORT 8989

int main(int argc, const char* argv[])
{
    int lfd, cfd;
    struct sockaddr_in serv_addr, clien_addr;
    int serv_len, clien_len;

    // 创建套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in 
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                   // 地址族 
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(SERV_PORT);            // 设置端口 
    serv_len = sizeof(serv_addr);
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    // poll结构体
    struct pollfd allfd[1024];
    int max_index = 0;
    // init
    for(int i=0; i<1024; ++i)
    {
        allfd[i].fd = -1;
        allfd[i].events = POLLIN;
    }
    allfd[0].fd = lfd;

    while(1)
    {
        int i = 0;
        int ret = poll(allfd, max_index+1, -1); 
        if(ret == -1)
        {
            perror("poll error");
            exit(1);
        }

        // 判断是否有连接请求
        if(allfd[0].revents & POLLIN)
        {
            clien_len = sizeof(clien_addr);
            // 接受连接请求
            int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
            printf("============\n");

            // cfd添加到poll数组
            for(i=0; i<1024; ++i)
            {
                if(allfd[i].fd == -1)
                {
                    allfd[i].fd = cfd;
                    break;
                }
            }
            // 更新最后一个元素的下标
            max_index = max_index < i ? i : max_index;
            if(--ret <= 0)
                continue;
        }

        // 遍历数组
        for(i=1; i<=max_index; ++i)
        {
            int fd = allfd[i].fd;
            if(fd == -1)
            {
                continue;
            }
            if(allfd[i].revents & POLLIN)
            {
                // 接受数据
                char buf[1024] = {0};
                int len = recv(fd, buf, sizeof(buf), 0);
                if(len == -1)
                {
                    perror("recv error");
                    exit(1);
                }
                else if(len == 0)
                {
                    allfd[i].fd = -1;
                    close(fd);
                    printf("客户端已经主动断开连接。。。\n");
                }
                else
                {
                    printf("recv buf = %s\n", buf);
                    for(int k=0; k<len; ++k)
                    {
                        buf[k] = toupper(buf[k]);
                    }
                    printf("buf toupper: %s\n", buf);
                    send(fd, buf, strlen(buf)+1, 0);
                }
                if(--ret <= 0)
                    break;
            }
        }
    }

    close(lfd);
    return 0;
}

 

Guess you like

Origin blog.csdn.net/mengyujia1234/article/details/92838065