嵌入式第三十五天

一、TCP

(1)粘包问题

(2)包头组成(源端口号,目的端口,序列号,确认号,校验和,标志位,滑动窗口大小,紧急指针等)

序号:发送数据的编号
确认号:接收到数据的编号(只有当ACK为1时,该位有效)、确认号即想要让对方下次发送数据的序号
数据偏移:拆包组包过程中标识该包的偏移量

(3)TCP和UDP

1.UDP实现方式简单
  资源开销比较小 
  UDP不安全、不可靠
  UDP是无连接的,面向数据包的传输方式

2.TCP实现方式复杂
  资源开销比较大 
  TCP安全、可靠 
  TCP是面向连接的,面向字节流传输方式

二、http协议

(1)客户端如何拿到服务器中的网页文件?

1.客户端向主机发送TCP链接请求
2.服务器收到请求后,与客户端链接成功
3.客户端向发送HTTP请求报文,告诉服务器想要的数据
4.服务器回复HTTP响应报文,将客户端要的数据发回
5.双方关闭通信 

三、IO和阻塞

(1)多路复用

select:监听文件描述符集合,将所有要监听的事件加入集合中,使用select监听所有事件,当集合中有事件发生, select不再阻塞,同时select会将产生事件的文件描述符留在集合中,而把没有产生事件的文件描述符从集合中踢出,所以留在集合中的文件描述即为产生事件的文件描述符,对其处理即可。

(2)多路复用代码

int CreateListenSocket(const char *pip, int port)
{
    int sockfd = 0;
    int ret = 0;
    struct sockaddr_in seraddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        return -1;
    }

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = inet_addr(pip);
    ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (-1 == ret)
    {
        return -1;
    }

    ret = listen(sockfd, 10);
    if (-1 == ret)
    {
        return -1;
    }

    return sockfd;
}

int HandleConnection(int confd)
{
    char tmpbuff[4096] = {0};
    ssize_t nsize = 0;

    nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }
    else if (0 == nsize)
    {
        return 0;
    }

    printf("RECV:%s\n", tmpbuff);

    sprintf(tmpbuff, "%s --- echo", tmpbuff);

    nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }

    return nsize;
}

int main(void)
{
    int sockfd = 0;
    int confd = 0;
    int ret = 0;
    fd_set rdfds;
    fd_set tmpfds; //读文件描述符
    int nready = 0;
    int maxfd = 0; //最大文件描述符
    int i = 0;

    //创建监听套接字
    sockfd = CreateListenSocket(SER_IP, SER_PORT);
    if (-1 == sockfd)
    {
        printf("创建监听套接字失败\n");
        return -1;
    }

    //将sockfd加入监听集合中
    FD_ZERO(&rdfds); //文件描述符集合清零
    FD_SET(sockfd, &rdfds);//将sockfd加入文件描述符集合中
    maxfd = sockfd;

    while (1)
    {
        //开始监听
        tmpfds = rdfds;
        nready = select(maxfd+1, &tmpfds, NULL, NULL, NULL);
        if (-1 == nready)
        {
            perror("fail to select");
            return -1;
        }

        //如果sockfd产生事件,处理新的连接请求,并将新的文件描述符加入集合,下次一起监听
        if (FD_ISSET(sockfd, &tmpfds))
        {
            confd = accept(sockfd, NULL, NULL);
            if (-1 == confd)
            {
                FD_CLR(sockfd, &rdfds);
                close(sockfd);
                continue;
            }   

            maxfd = maxfd > confd ? maxfd : confd;
            FD_SET(confd, &rdfds);
        }

        //遍历所有已经连接的客户端中是否有事件发生
        for (i = sockfd+1; i <= maxfd; i++)
        {
            if (FD_ISSET(i, &tmpfds)) // 判断i是否仍在文件描述集合中
            {
                ret = HandleConnection(i);
                if (-1 == ret)
                {
                    printf("连接异常\n");
                    FD_CLR(i, &rdfds);  //将i从集合中清除
                    close(i);
                    continue;
                }
                else if (0 == ret)
                {
                    printf("连接断开\n");
                    FD_CLR(i, &rdfds);
                    close(i);
                    continue;
                }
            }
        }
    }
    
    close(sockfd);

    return 0;
}
int CreateTcpConnection(const char *pip, int port)
{
    int sockfd = 0;
    int ret = 0;
    struct sockaddr_in seraddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = inet_addr(SER_IP);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        return -1;
    }

    ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (-1 == ret)
    {
        return -1;
    }

    return sockfd;
}

int HandleConnection(int sockfd)
{
    char tmpbuff[4096] = {0};
    static int cnt = 0;
    ssize_t nsize = 0;

    sprintf(tmpbuff, "hello world --- %d", cnt);
    nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }
    cnt++;

    memset(tmpbuff, 0, sizeof(tmpbuff));
    nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);  
    if (-1 == nsize)
    {
        return -1;
    }
    else if (0 == nsize)
    {
        return 0;
    }
    
    printf("RECV:%s\n", tmpbuff);

    return nsize;
}

int main(void)
{
    int sockfd = 0;
    int ret = 0;

    sockfd = CreateTcpConnection(SER_IP, SER_PORT); //改自己的IP和端口
    if (-1 == sockfd)
    {
        printf("连接服务器异常\n");
        return -1;
    }

    while (1)
    {
        ret = HandleConnection(sockfd);
        if (-1 == ret)
        {
            printf("连接出错!\n");
            break;
        }
        else if (0 == ret)
        {
            printf("连接关闭\n");
            break;
        }

        sleep(1);
    }
    
    close(sockfd);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值