socket编程实现简易服务器与客户端温度传输

一、socket编程实现服务器与客户端连接

1.了解TCP/IP协议和服务器和客户端的通信原理

TCP/IP协议本人还不太懂,有需要者请查看

太棒了!TCP/IP协议 (图解+秒懂+史上最全)这位博主的文章,

总的来说一张图概括:

2.创建服务器和客户端

1)创建服务器

从上图可知,创建服务器所要用到的函数为

socket()

创建套接字文字描述法server_fd

bind()

把文字描述符与端口PORT绑定起来

listen()监听

accept()

阻塞,一直有客户端连接才会连通

read()/write()

需要注意的是服务器写,客户端就读

再者,read()和 write()函数的使用方法需要仔细查看,本人在使用读写过程中就犯了许多错误

write()/read()

close()关闭文字描述法

具体代码如下:

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


#define PORT 8080
#define TEST_TXT "11111"
#define TEMPERATURE "Temperature is %.2f"
int Get_DS18B20_Temp(float *temp);


int main(int argc,char **agrv)
{	
	int server_fd,client_fd;
	struct sockaddr_in serv_addr;
	struct sockaddr_in cli_addr;
	socklen_t cliaddr_len;
	int addrlen = sizeof(serv_addr);
	char buf[1024];
	float temp;
	int client_rv;
	char message[1024];

	//创建 socket 文件描述符
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(server_fd < 0)
	{
		printf("Create socket failure: %s\n", strerror(errno));
		return -1;
	}
	printf("Create socket fd[%d]\n", server_fd);
	
	// 设置 socket 选项, 允许多个连接相同的端口
	/*if(setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
	{
		printf("Set more port failure: %s\n", strerror(errno));
		goto cleanup;	
	}*/
	
	memset(&serv_addr, 0 ,sizeof(serv_addr)); //初始化serv_addr 的值
	serv_addr.sin_family = AF_INET; //ipv4
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(PORT); //htons():将服务器ip转为客户端ip

	//绑定 socket 到指定的地址和端口
	if (bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Create socket failure: %s\n", strerror(errno));
		return -2;
	}
	printf("Create[%d] bind on port[%d] for all IP address OK\n", server_fd, PORT);

	//设置监听,连接
	listen(server_fd, 3);
	
	//等待客户端连接
	while(1)
	{
		printf("\nStar waiting and accept new client connect ...\n", server_fd);
		client_fd = accept(server_fd, (struct sockaddr*)&cli_addr, &cliaddr_len);
		if(client_fd < 0)
		{
			printf("create accept failure: %s\n", strerror(errno));
			return -2;
		}
		printf("Accept new client[%s:%d] with fd [%d]\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), client_fd);
	
	
		//调用Get_DS18B20_Temp函数读取温度
		if((Get_DS18B20_Temp(&temp)) < 0)
		{
			printf("ds18b20 get temperature failure\n");
			return -3;
		}
		printf("Temperature is:%.3f C\n", temp);
		
		//测试用例	
		/*if((write(client_fd, TEST_TXT, strlen(TEST_TXT))) < 0)
		{
			printf("write faile: %s\n", strerror(errno));
			goto cleanup;
		}
		printf("write ok");*/
		
		//将temp的值转换为字符串
		int len = snprintf(buf, sizeof(buf), TEMPERATURE, temp);
		if(len < 0 || len >= sizeof(buf))
		{
			fprintf(stderr,"error converting temp to string\n");
			exit(0);
		}
		printf("%s\n", buf);

		//读取文件内容并发送给客户端
		if(write(client_fd, buf, sizeof(buf)) < 0)
		{
			printf("write data to client [%d] failure: %s\n", PORT, strerror(errno));
			goto cleanup;
		}

		/*snprintf(message, sizeof(message), "%d", temp);
		while(temp > 0)
		{
			send(client_fd, buf, strlen(message), 0);
			memset(buf, 0, sizeof(buf));
		}*/
		
		//读取client端返回的数据
		memset(buf, 0, sizeof(buf));
		if((client_rv = read(client_fd, buf, sizeof(buf))) < 0)
		{
			printf("read data from client failure: %s\n", strerror(errno));
			goto cleanup;
		}
		else if(client_rv == 0)
		{
			printf("server connect to client get dis\n");
			goto cleanup;
		}
		printf("read %d bytes data from client: %s\n", client_rv, buf);
		

		sleep(1);
		close(client_fd);
	}	
	
cleanup:
	close(server_fd);

	return 0;	
}


int Get_DS18B20_Temp(float *temp)
{
	int fd = -1;
	int rv = -1;
	char path[50] = "/sys/bus/w1/devices/";
	char dir_name[20];
	DIR *dirp;
	int found = -1;
	struct dirent *direntp;
	char buf[128];
	char *ptr;
	
	memset(dir_name, 0, sizeof(dir_name));
	memset(buf, 0, sizeof(buf));

	if((dirp = opendir(path)) == NULL)
	{
		printf("open dir '%s' failure: %s\n", path, strerror(errno));
		return -1;
	}
	printf("open dir '%s' successfully\n", path);


	while((direntp = readdir(dirp)) != NULL)
	{
		if(strstr(direntp->d_name, "28-") == NULL)
			continue;

		strncpy(dir_name, direntp->d_name,strlen(direntp->d_name));
		printf("Find file:%s\n", dir_name);
		found = 1;
		break;
	}
	closedir(dirp);

	if(found == -1)
	{
		printf("can not find ds18b20 in '%s'\n", path);
		return -2;
	}

	strncat(path, dir_name, strlen(dir_name));
	strncat(path,"/w1_slave", sizeof(path)-strlen(path));

	if((fd = open(path, O_RDONLY)) < 0)
	{
		printf("open file '%s'\n", path, strerror(errno));
		return -3;
	}
	printf("open file '%s' fd[%d] successfully\n", path, fd);

	if((rv = read(fd, buf, sizeof(buf))) < 0)
	{
		printf("read data from file '%s' failure: %s\n", path, strerror(errno));
		rv = -4;
		goto cleanup;
	}
	printf("read %dB data from file '%s'\n", rv, path);
	
	if((ptr = strstr(buf, "t=") + 2) == NULL)
	{
		printf("find data failure: %s\n", strerror(errno));
		rv = -5;
		goto cleanup;
	}

	*temp = atof(ptr)/1000;

cleanup:
	if(fd > 0)
	close(fd);


	return rv;
}

2)创建客户端

创建客户端流程为:

  1. socket()
  2. connect()创建连接
  3. write()/read()
  4. read()/write()
  5. close()

客户端代码:

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

#define PORT 8080
#define SERVER_IP "127.0.0.1"


int main(int argc, char **argv)
{
	int conn_fd, value_read;
	struct sockaddr_in serv_addr;
	char buf[1024];
	int rv = -1;
	double temp;

	//创建 connet 的文件描述符
	if((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		printf("create conn_fd failure: %s\n", strerror(errno));
		return -1;
	}
	printf("Create conn_fd ok\n");	

	//将ipv4地址从点分十进制转换为二进制
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	inet_aton( SERVER_IP, &serv_addr.sin_addr);

	
	if((connect(conn_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0)
	{
		printf("create connect failure: %s\n", strerror(errno));
		return -2;
	}
	printf("\nCreate connect OK\n");

	memset(buf, 0, sizeof(buf));
	if((rv = read(conn_fd, buf, sizeof(buf))) < 0)
	{
		printf("read data from server socket[%d] failure: %s\n", conn_fd, strerror(errno));
		close(conn_fd);
	}
	else if(rv == 0)
	{
		printf("server socket[%d] disconnected\n", conn_fd);
		close(conn_fd);
	}	
	printf("read %d bytes data from server[%d] and echo it back: '%s'\n", rv, conn_fd, buf);

	if((write(conn_fd, buf, rv)) < 0)
	{
		printf("write %d bytes data back to server[%d] failure: %s\n", rv, conn_fd, strerror(errno));
		close(conn_fd);
	}


	/*while((value_read = read(conn_fd, buf, sizeof(buf))) > 0)
	{
		printf("%s", buf);
		memset(buf, 0, sizeof(buf));
	}*/


	close(conn_fd);	

	return 0;
}

需要注意的是,int Get_DS18B20_Temp函数传回的是float类型的变量,需要使用snprintf()函数将传回来的temp变量转换为char字符类型进行传输,并以二进制类型存在buf缓存空间内。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值