Socket再学习——开发板ds18b20获取温度值并上报服务器

经过一段时间的学习、积累,自己对于物联网、计算机网络、socket编程等相关的领域和知识有了新的理解,网络部分一直是重中之重。因此重新再学习了Linux下的socket,并结合了一个简单的实际例子再来学习client端与server端工作流程。

===========================================

文件描述符:实际上就是Linux内核给分配的“称谓”,而在我们的TCP通讯中,会有多个文件描述符需要处理。
比如:
listenfd:监听描述符
connectfd:请求连接描述符
accept:接受连接描述符
read/write/recv/send…:IO描述符

服务器建立连接的流程和涉及到的函数:socket()、bind()、listen()、accept()、connect()、close()。

结构体struct sockaddr_in :网络通讯五元组,本端IP,本端端口、对端IP、对端端口、协议类型。

这里写图片描述
参考这张图便能了解client和server之间之间是如何进行交互的了。

===========================================
int socket(int domain, int type, int protocol);
向内核申请一个套接字,设置该套接字协议类型。

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
为套接字绑定IP和端口

int listen(int sockfd, int backlog);
以socket套接字和该套接字绑定的IP信息listen在内核开启监听,并返回监听描述符。这里代码是不阻塞的,但是内核一直在监听对应的端口。

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
连接请求,此时代码是阻塞的。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
接受连接的请求,代码阻塞。就是从listen中取描述符。

int close(int fd);
关闭描述符。

这里写图片描述
是不是就是类似我们熟悉的三次握手呀。

Client请求时间是不确定的,当多个请求到Server时,处于请求队列,等待listen的端口逐个处理至就绪队列。
connect处于阻塞态等待请求从listen的就绪队列被accept调度返回具体用于数据传输的accept_fd描述符。
accept处于阻塞态,当请求队列为空或处理完毕时。
所以,三次握手由connet发起,accept结束,途中经历listen的队列维护。

下面贴出代码,功能是由在开发板上的DS18B20采集了温度数据,上报到服务器,并且显示当前的时间。当然,前提是开发板已经使能了DS18B20的驱动,否则是跑不起应用程序的。
DS18B20的驱动编写可以参考这里:http://blog.csdn.net/u010944778/article/details/48058433

temp_server.c:

/*********************************************************************************
 *      Copyright:  (C) 2017 TangBin<[email protected]>
 *                  All rights reserved.
 *
 *       Filename:  temp_server.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(06/18/2017)
 *         Author:  TangBin <[email protected]>
 *      ChangeLog:  1, Release initial version on "06/18/2017 08:22:56 PM"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <time.h>

#define MAXLINE 1024
#define PORT 8200
#define BUFFSIZE 2048

int main (int argc, char **argv)
{
    int listenfd, connfd;
    int n;
    char buf[BUFFSIZE];
    struct sockaddr_in servaddr;

    if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("create socket error:");
        exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("bind error:");
        exit(0);
    }

    if(listen(listenfd, 10) < 0)
    {
        perror("listen error:");
        exit(0);
    }

    printf("waiting client's request... ...\n");
    while(1)
    {
        memset(&buf, 0, sizeof(buf));
        time_t rawtime;
        struct tm* ptime;
        char time_arr[100];
        time(&rawtime);
        ptime = localtime(&rawtime);
        strftime(time_arr, 20, "%y-%m-%d %I:%M:%S", ptime);

        if((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) < 0)
        {
            perror("accept error:");
            continue;
        }
        n = recv(connfd, buf, MAXLINE, 0);
        strcat(buf, "℃\0");
        printf("temperature :%s\n", buf);
        printf("%s\n",time_arr);
    }
    close(connfd);

    return 0;
} /* ----- End of main() ----- */

temp_client.c:

/*********************************************************************************
 *      Copyright:  (C) 2017 TangBin<[email protected]>
 *                  All rights reserved.
 *
 *       Filename:  temp_client.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(06/19/2017)
 *         Author:  TangBin <[email protected]>
 *      ChangeLog:  1, Release initial version on "06/19/2017 12:52:25 PM"
 *                 
 ********************************************************************************/

#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAXLINE 1024
#define PORT 8200
float get_temp(void)
{
    int fd;
    int data = 0;
    float temperature = 0;
    unsigned char buff[2];

    if((fd=open("/dev/ds18b20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
    {
        perror("open device ds18b20 failed.");
        exit(1);
    }

    printf("open ds18b20 success.");

    read(fd, buff, sizeof(buff));
    data = ((int)buff[1]) << 8;  //高8位移动到16BITS的高8位
    data |= (int)buff[0];   //合并低8位到温度读值
    temperature = ((float)data)*0.0625;  
    /*DS18B20的温度操作是使用16位,也就是说分辨率是0.0625;要求出正数的十进制值,必须将读取到的LSB字节,MSB字节进行整合处理,然后乘以0.0625即可*/

    close(fd);
    printf("emperature is %4f \r\n",temperature);

    return temperature;
}

int main (int argc, char **argv)
{
    float res;
    int socketfd;
    char temp[50];
    char s_line[MAXLINE];
    struct sockaddr_in servaddr;

    if(2 != argc)
    {
        printf("please input: ./client <ipaddr>\n");
        return 0;
    }

    if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("create socket error: %s(errno: %d).\n", strerror(errno), errno);
        return 0;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);

    if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)   //点分十进制ip转换为点分二进制ip
    {
        printf("inet_pton error for %s.\n", argv[1]);
        return 0;
    }
    if(connect(socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }
    res = get_temp();
    gcvt(res ,4 ,temp);    //浮点型数转换为字符串,参数1:被转换的值;参数2:存储的有效数字位数;参数3:结果的存储位置。
    memset(s_line ,0, sizeof(s_line));
    strcpy(s_line, temp);

    if(send(socketfd, s_line, strlen(s_line), 0) < 0)   //将数据发送到服务器端
    {
        printf("send error:%s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    close(socketfd);

    return 0;
} /* ----- End of main() ----- */

测试结果,用的是实验室的服务器和自己的开发板fl2440:
这里写图片描述
(其中connect error是因为在服务器上我的server程序没运行)
这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章