나미/C

https post

규남 2021. 5. 27. 10:38
반응형


요즘 c언어가 별로 없다 보니 생각보다 자료나 연동에 있어서 고생을 많이 한다...

이번에 프로젝트에서 아두이노 라즈베리파이 plc.. 등등 연동하다가 https 웹소켓을 함께 연동하는 일이 생겨서

겸사겸사 올려본다.

/*==============================================================================================/
 *
 *  Copyright (C) 2021 Qsentech Software Corp Reaserch Institute
 *  All rights reserved.
 *
 *  Author : Lee Kyu Nam (nasanx2001@naver.com)
 *
 *==============================================================================================*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <curl/curl.h>
#include <time.h>
#include <unistd.h>
#include <sys/shm.h>

#include "cJSON.h"


#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE 1

#ifdef _WIN32
#undef snprintf
#define snprintf _snprintf
#endif

#define _status_item	28

typedef struct tm 	tm;

int old_min = 0;

struct _dev *dev_shm;
void *dev_shared_memory = (void *)0;
#define DEV_SHM_KEY		3131

struct _dev
{
	char polling_data[2000];
	int polling_flag;
	char ack_data[2000];
	int ack_flag;
};

struct _timer *timer_shm;
void *timer_shared_memory = (void *)0;
#define TIMER_SHM_KEY	2121

struct _timer
{
	int yyyy;
	int mm;
	int md;
	int hour;
	int min;
	int sec;
};

struct _set_Value *set_shm;
void *set_shared_memory = (void *)0;
#define SET_SHM_KEY	1111

struct _set_Value
{
	int sensor1;
    int sensor2;
    int sensor3;
    int sensor4;
    int sensor5;
};


/* Post JSON data to a server.
name and value must be UTF-8 strings.
Returns TRUE on success, FALSE on failure.
*/


// test용
//========================================================================
char *key_name[] = {"systemDate", "systemId", "sensor1", "sensor2", "sensor3", "sensor4", "sensor5"};


struct MemoryStruct
{
	char *memory;
	size_t size;
};

static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size = nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;
	
	mem->memory = realloc(mem->memory, mem->size + realsize + 1);
	if(mem->memory == NULL)
	{
		printf("memory error\n");
		return 0;
	}
	
	memcpy(&(mem->memory[mem->size]), contents, realsize);
	mem->size += realsize;
	mem->memory[mem->size] = 0;
	
	return realsize;
}



int PostJSON(int item)
{
	int retcode = FALSE;
	cJSON *root = NULL;
	char *json = NULL;
	CURL *curl = NULL;
	CURLcode res = CURLE_FAILED_INIT;
	char errbuf[CURL_ERROR_SIZE] = { 0, };
	struct curl_slist *headers = NULL;
	char agent[1024] = { 0, };
	int i = 0;
	char timer[18];
	char *p;
	char buff[400];
	long statLong ;
	
	FILE *fp;
	fp = fopen("/home/ubuntu/log/post.txt", "a+");
	
	sprintf(timer, "%04d%02d%02d %02d:%02d:%02d", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour, timer_shm->min, timer_shm->sec);
	printf("%s\n", timer);

	root = cJSON_CreateObject();
	if(!root) {
		fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d] Error: cJSON_CreateObject failed.\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec);
		goto cleanup;
	}
	
	cJSON_AddStringToObject(root, key_name[i++], timer);
	
	memset(buff, 0x00, sizeof(buff));
	memcpy(buff, dev_shm->polling_data, strlen(dev_shm->polling_data));
	
	p = strtok(buff, ", ");
	while(p != NULL)
	{
		if(i < 7)
		{
			if((strcmp(p, "ex") != 0)) // ETX 테스트용
			{
				cJSON_AddStringToObject(root, key_name[i++], p);
			}
		}
		p = strtok(NULL, ", ");
	}
	
	json = cJSON_PrintUnformatted(root);
	if(!json) {
		fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d] Error: cJSON_PrintUnformatted failed.\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec);
		goto cleanup;
	}

	curl = curl_easy_init();
	if(!curl) {
		fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d] Error: curl_easy_init failed.\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec);
		goto cleanup;
	}
  
	// debug
	// printf("json = %s\n", json);

	curl_easy_setopt(curl, CURLOPT_CAINFO, "tset.crt");

	snprintf(agent, sizeof(agent), "libcurl/%s",
           curl_version_info(CURLVERSION_NOW)->version);
	agent[sizeof(agent) - 1] = 0;
	curl_easy_setopt(curl, CURLOPT_USERAGENT, agent);
	
	headers = curl_slist_append(headers, "Expect:");
	headers = curl_slist_append(headers, "Content-Type: application/json");
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
	
	
	
	/* This is a test server, it fakes a reply as if the json object were
		created */
	curl_easy_setopt(curl, CURLOPT_URL,
					"https://xxx-xxxxxx/xxx.com/xx/xxxxxx");
	
	
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
	curl_easy_setopt (curl, CURLOPT_FORBID_REUSE, 1L);
	
	res = curl_easy_perform(curl);
	if(res != CURLE_OK) {
		size_t len = strlen(errbuf);
		fprintf(fp, "\nlibcurl: (%d)\n ", res);
		if(len)
		fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d]%s%s\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec, errbuf, ((errbuf[len - 1] != '\n') ? "\n" : ""));
		fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d]%s\n\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec, curl_easy_strerror(res));
		//goto cleanup;
	}
	else{
		if( CURLE_OK == curl_easy_getinfo( curl , CURLINFO_HTTP_CODE , &statLong ) ){
			// printf("[%04d-%02d-%02d %02d:%02d:%02d] RCV_HTTP_CODE : %ld\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,
			// timer_shm->min, timer_shm->sec, statLong);
			fprintf(fp, "[%04d-%02d-%02d %02d:%02d:%02d] RCV_HTTP_CODE : %ld\n", timer_shm->yyyy, timer_shm->mm, timer_shm->md, timer_shm->hour,timer_shm->min, timer_shm->sec, statLong);
			
			dev_shm->polling_flag = 0;
		}
	}
	
	retcode = TRUE;
	cleanup:
	fclose(fp);
	curl_slist_free_all(headers);
	curl_easy_cleanup(curl);
	cJSON_Delete(root);
	free(json);
	return retcode;
}


void timer_count()
{
	time_t t = time(NULL);
	struct tm tm = *localtime(&t);
	
	timer_shm->yyyy = tm.tm_year+1900;
	timer_shm->mm = tm.tm_mon+1;
	timer_shm->md = tm.tm_mday;
	timer_shm->hour = tm.tm_hour;
	timer_shm->min = tm.tm_min;
	timer_shm->sec = tm.tm_sec;
}


int main(int argc, char *argv[])
{
	int dev_shmid;
	int timer_shmid;
	int set_shmid;

//=========================================================================================	
	dev_shmid = shmget((key_t)DEV_SHM_KEY, sizeof(char), 0666 | IPC_CREAT);
	if(dev_shmid == -1)
	{
		perror("dev shmget fail");
		exit(0);
	}
	dev_shared_memory = shmat(dev_shmid, (void *)0, 0);
	if(dev_shared_memory == (void *)-1)
	{
		perror("dev shmat fail");
		exit(0);
	}
	dev_shm = (struct _dev *)dev_shared_memory;	
//=========================================================================================

//=========================================================================================	
	timer_shmid = shmget((key_t)TIMER_SHM_KEY, sizeof(char), 0666 | IPC_CREAT);
	if(timer_shmid == -1)
	{
		perror("timer shmget fail");
		exit(0);
	}
	timer_shared_memory = shmat(timer_shmid, (void *)0, 0);
	if(timer_shared_memory == (void *)-1)
	{
		perror("timer shmat fail");
		exit(0);
	}
	timer_shm = (struct _timer *)timer_shared_memory;	
//=========================================================================================

//=========================================================================================
	set_shmid = shmget((key_t)SET_SHM_KEY, sizeof(char), 0666 | IPC_CREAT);
	if(set_shmid == -1)
	{
		perror("set shmget fail");
		exit(0);
	}
	set_shared_memory = shmat(set_shmid, (void *)0, 0);
	if(set_shared_memory == (void *)-1)
	{
		perror("set shmat fail");
		exit(0);
	}
	set_shm = (struct _set_Value *)set_shared_memory;
//=========================================================================================
	
	while(1)
	{
		sleep(1);
		timer_count();
		
		if(timer_shm->min != old_min)
		{
			old_min = timer_shm->min;
			
			if(curl_global_init(CURL_GLOBAL_ALL)) {
				fprintf(stderr, "Fatal: The initialization of libcurl has failed.\n");
				return EXIT_FAILURE;
			}
	
			if(atexit(curl_global_cleanup)) {
				fprintf(stderr, "Fatal: atexit failed to register curl_global_cleanup.\n");
				curl_global_cleanup();
				return EXIT_FAILURE;
			}
			
			if(dev_shm->polling_flag == 1)
			{
				if(!PostJSON(_status_item)) {
					fprintf(stderr, "Fatal: PostJSON failed.\n");
					return EXIT_FAILURE;
				}
			}			
		}
	}
	
	
	 return EXIT_SUCCESS;
}

참고로 crt 인증서의 경우 해당 인증서 경로에 접속해야하는 서버의 인증서를 직접 받는 방법과

리눅스에서 해당 서버인증서를 확인하여 긁어오는 방법도 있다.

나 같은 경우는 직접 인증서를 해당사이트에 가서 긁어오는 방식을 택해서 작업을 하였다.

git에 cJson을 활용한 부분이고 json의 경우 여러가지 lib과 또는 직접 구현해도 별로 어렵지 않으니 ..

위 소스의 경우 공유메모리를 사용하는 부분이 포함되어 있으니 이부분은 제외하면 될꺼같다. 

프로세스가 3개이상 동작중에 데이터를 서로 공유해야하는 상황때문에 이렇게 코딩을 하였으니 참고바람.

이상 

728x90
반응형

'나미 > C' 카테고리의 다른 글

함수 포인터(간단하게)  (0) 2023.08.27
strsep  (0) 2018.10.15
문자열 자르기 strtok  (0) 2018.02.05
strtol 함수  (0) 2018.02.05
C언어 텍스트 컬러  (0) 2017.07.12
switch case문안에 변수사용하기  (0) 2017.06.21
C언어 파일읽기  (0) 2017.06.21
공유메모리 key 하나로 구조체 배열할당하기  (0) 2017.03.17
hexTobinary(2)  (0) 2017.03.08
hexTobinary  (0) 2016.12.16