首页 > 系统相关 >通过Linux的socket套接字实现客户端与服务器端的通信

通过Linux的socket套接字实现客户端与服务器端的通信

时间:2022-10-22 21:15:10浏览次数:58  
标签:addr server char socket fd Linux include buf 服务器端

具体案例:使用树莓派ds18b20温度传感器实现温度上报

  • 首先需要获得传感器文件中保存的温度信息:

  温度信息通常保存在路径为“/sys/bus/w1/devices/28-xxxxxxxxxxxx/w1_slave”的文件中:  (这里的28-xxxxxxxxxxxx为产品序列号因此我们需要在代码中解决序列号不同导致程序复用性低的问题)

  可以通过cat命令显示当前温度信息:

  cat w1_slave

     crc为循环冗余校验码;实际温度即为t/1000即27.625℃

 

  以下为服服务器端的代码    

1 #include <stdlib.h>
  2 #include <sys/types.h>
  3 #include <sys/socket.h>
  4 #include <errno.h>
  5 #include <stdio.h>
  6 #include <string.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <unistd.h>
 10 #include <sys/stat.h>
 11 #include <fcntl.h>
 12 #include <dirent.h>
 13 
 14 
 15 #define SERVER_IP       "127.0.0.1"   //ip地址先设置为本机环回地址,端口随便,先本地测试一下能否正确得到温度
 16 #define SERVER_PORT     1234517 
 18 
 19 float getTemper(){
 20 
 21     char        file_path[128]="/sys/bus/w1/devices/";
 22     char        buf[128];
 23     char        *temper_str   = NULL;  //用于接收字符串类型的温度数据
 24     int         file_fd       = -1;   //文件描述符
 25     float       temper        = 0;    //接收温度的浮点数
 26 
 27 
 28     DIR        *DIR_str = NULL;
 29     struct  dirent *dirent_str   = NULL;
 30 
 31     DIR_str = opendir(file_path);
 32     if(!DIR_str)
 33     {
 34         printf("directory open failed :%s",strerror(errno));
 35         return -1;
 36     }
 37 
 38     while(dirent_str = readdir(DIR_str))
 39     {
 40         if(strstr(dirent_str -> d_name,"28-"))
 41         {
 42             bzero(&buf,sizeof(buf));
 43             strncpy(buf,dirent_str->d_name,sizeof(buf));
 44         }
 45 
 46     }
 47 
 48     strncat(file_path,buf,sizeof(file_path));
 49     strncat(file_path,"/w1_slave",sizeof(file_path)-1);
 50 
 51     file_fd =open(file_path,O_RDONLY);
 52     if(file_fd < 0)
 53     {
 54         printf("file open failed:%s\n",strerror(errno));
 55 
 56     }
 57 
 58     bzero(&buf,sizeof(buf));
 59 
 60     if(!read(file_fd,buf,sizeof(buf)))
 61     {
 62         printf("read file failed: %s\n",strerror(errno));
 63     }
 64 
 65     temper_str = strstr(buf,"t=");
 66     if(temper_str == NULL)
 67     {
 68         printf("can not find 't=' \n");
 69     }
 70 
 71     temper_str += 2;
 72     temper = atof(temper_str);
 73     printf("acquire right now temperature is:%f\n",temper/1000);
 74     return temper/1000;
 75 }   
    //以上为de18b20获取温度的代码 76 77 78 79 80 int main(int argc,char **argv){ 81 int client_fd = -1; 82 int return_value = -1; 83 84 struct sockaddr_in server_addr ; 85 char buf[512] ; 86 char string[20] ; 87 float return_temper = getTemper(); 88 sprintf(string,"%f",return_temper); 89 90 bzero(&server_addr,sizeof(server_addr)); 91 server_addr.sin_family = AF_INET; 92 server_addr.sin_port = htons(SERVER_PORT); 93 //inet_aton(SERVER_IP,&server_addr.sin_addr); 94 inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr); 95 96 struct sockaddr *server_address = (struct sockaddr*)&server_addr; 97 98 client_fd=socket(AF_INET,SOCK_STREAM,0); 99 if(client_fd < 0) 100 { 101 printf("socket created failed: %s",strerror(errno)); 102 return -1; 103 } 104 printf("socket created successfully\n"); 105 106 return_value = connect(client_fd,(struct sockaddr*)&server_addr,sizeof(server_addr)); 107 // return_value = connect(client_fd,server_address,sizeof(server_addr)); 108 109 if(return_value < 0) 110 { 111 printf("connect failed :%s\n",strerror(errno)); 112 return -2; 113 } 114 printf("connect successful\n"); 115 116 bzero(&buf,sizeof(buf)); 117 118 return_value = write(client_fd,string,strlen(string)); 119 120 read(client_fd,string,strlen(string)); 121 122 printf("%s\n",string); 123 124 close (client_fd); 125 126 return 0; 127 }

 

*DIR 结构体

函数   DIR *opendir(const char *path)

打开文件目录,返回指向DIR结构体的指针

*dirent结构体

定义:

struct dirent
{
  long d_ino;             /* inode number 索引节点号 */
  off_t d_off;              /* offset to this dirent 在目录文件中的偏移 */
  unsigned short d_reclen;       /* length of this d_name 文件名长 */
  unsigned char d_type;        /* the type of d_name 文件类型 */
  char d_name [NAME_MAX+1];    /* file name (null-terminated) 文件名,最长255字符 */                                 
}

它指向目录以及目录中的所有文件,其中搭配使用的    readdir( )函数:       成功则返回下个目录进入点. 有错误发生或读取到目录文件尾则返回NULL.

简单来说就是DIR结构体通过opendir打开目录(文件夹),通过dirent索引可以获得需要的文件名

 

 

 

不知到服务器的ip地址,但是知道域名,可以通过域名解析获取服务器ip地址

方法一:

  • 添加头文件并注释掉测试地址

 

#include <netdb.h>
//#define SERVER_IP             "127.0.0.1"

 

  • 在main函数增加hosten结构体
 struct  hostent         *host = gethostbyname(serverName);
  • 将注释掉的ip地址重新声明

 

char                     *SERVER_IP       =NULL;
  • 一个域名可能对应多个ip
for(int i = 0;host->h_addr_list[i];i++){

                SERVER_IP = inet_ntoa(*(struct in_addr*)host->h_addr_list[i]);
        }

 

 

inet_ntoa()函数             将网络地址转换成“.”点隔的字符串格式

struct hostent
{
  char *h_name;        //正式主机名
  char **h_aliases;       //主机别名
  int h_addrtype;        //主机IP地址类型:IPV4-AF_INET
  int h_length;            //主机IP地址字节长度,对于IPv4是四字节,即32位
  char **h_addr_list;       //主机的IP地址列表     二级指针,哈人
};

 

 

 

以下为服务器端代码:

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


#define LISTEN_PORT     1299
#define BACKLOG         13


int main(int argc,char **argv){

        int             rv      = -1;
        int             listen_fd,client_fd = -1;
        struct sockaddr_in      server_addr;
        struct sockaddr_in      client_addr;
        socklen_t               client_addr_len;
        char                    buf[1024];

        listen_fd =socket(AF_INET,SOCK_STREAM,0);
        if(listen_fd<0){

                printf("create socket failed :%s\n",strerror(errno));
                return -1;

        }
        printf("socket create fd[%d]\n",listen_fd);

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

        if (bind(listen_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))<0){

                printf("create socket failed: %s\n",strerror(errno));
                return -2;

        }
        printf("socket[%d] bind on port [%d] for all IP address ok\n",listen_fd,LISTEN_PORT);


        listen(listen_fd,BACKLOG);



        while(1)
        {


                printf("\n Start waiting an accept new client connect...\n");
                client_fd = accept(listen_fd,(struct sockaddr*)&client_addr,&client_addr_len);
                if(client_fd <=0){

                        printf("accept new socket failure: %s\n", strerror(errno));
                         return -2;
                }
        printf("Accept new client[%s:%d] with fd [%d]\n", inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port), client_fd);

        memset(buf,0,sizeof(buf));
        if((rv = read(client_fd,buf,sizeof(buf)))<0){


                printf("read data from client socket[%d] failed:%s\n",client_fd,strerror(errno));
                close(client_fd);
                continue;

        }
        else if(rv ==0){

                printf("client socket [%d] disconnected",client_fd);
               close(client_fd);
                continue;              

        }

        printf("read %d bytes data from client [%d] and echo it back :'%s'\n",rv,client_fd,buf);

        if(write(client_fd,buf,rv) < 0){

                printf("Write %d bytes data back to client [%d] failed:%s\n",rv,client_fd,strerror(errno));
                close(client_fd);
        }

        sleep(1);
        close(client_fd);
      }
        close(listen_fd);


}

 

效果:客户端发过去后接收到服务器发回的数据

 

 

 服务器端接收到客户端发送的数据并发回相同内容

 

 

 

看得头晕,明天补下注释吧。。。

 

标签:addr,server,char,socket,fd,Linux,include,buf,服务器端
From: https://www.cnblogs.com/genm/p/16816349.html

相关文章

  • Linux 网络命令
    导图一.网络配置命令1.ifconfig- 查看网络接口信息 命令格式作用ficonfig来自于net-tools包,在不带任何选项和参数执行ifconfig命令时,将显示当前主机中已......
  • linux下使用gcc编译含gets()函数的程序
    网上有很多关于gets()会导致栈溢出之类的废话也许会有初学者望着千篇一律的回答茫然无错,以为真的就只能使用fgets()了 首先你要了解gets()函数有极大的风险其次,在gcc......
  • Linux、数据库、Redis、MongoDB统一管理平台!
    #一、开源项目简介基于DDD分层实现的web版linux(终端文件脚本进程)、数据库(mysqlpostgres)、redis(单机集群)、mongo统一管理操作平台# 二、开源协议使用Apache-2.0......
  • Linux执行jsp命令的时候报错:-bash: jps: command not found
    前言:在zookeeper学习的时候,执行jsp命令查看zookpper运行状态的时候发现报错:-bash:jps:commandnotfound翻阅了一大批文章,不是东拼西凑,就是缺斤少两,于是乎,本人萌生了......
  • Linux中的ssh服务
    一、ssh服务1.1、ssh基础简单说,SSH(SecureShell)是一种网络协议,用于计算机之间的加密登录。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种......
  • Linux 系统生产环境配置指南
    1.服务器基本配置1、物理服务器使用RAID1或RAID10磁盘配置,虚拟服务器不受此限制2、物理服务器操作系统使用整体物理硬盘3、虚拟服务器系统盘80G,数据盘按业务需求新增并附加2......
  • Linux网络服务——PXE网络批量装机+Kickstart无人值守安装
    1系统安装介绍1.1系统装机的三种引导方式1硬盘2光驱3网络1.2系统安装过程加载bootloader加载启动安装菜单加载内核和initrd系统加载根系统运行anaconda......
  • Linux命令
    1、查看磁盘空间:df2、查看CPU使用率:top3、查找文件:find-name4、查看文件:Vim/Cat5、查看进程:PSTOPPStree(以树的方式展示进程间的关系)6、查看端口号:netstatls......
  • 记一次SpringBoot整合WebSocket 找不到ServerEndpointExporter类的问题
    packagecom.mengxiangnongfu.cms.framework.configure;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Confi......
  • Linux防火墙的查看及端口的开放
    Linux防火墙的查看及端口的开发1.有关防火墙的基本操作#查看防火墙状态systemctlstatusfirewalld#开启防火墙systemctlstartfirewalld#临时关闭防火墙systemc......