While STM32 runs the LwIP protocol,How to implement 5 TCP connections? - tcp

Now,I am working with STM32F107+lwip.The aim is making a gateway which is used to exchange datas between ETHERNET and CAN. The UDP server is tested well.And now I want to increase the TCP server function,which can be permitted to establish 5 TCP connections.
My questions:
1 TCP connnection is tested ok,How to implement 5 TCP connections?
First,PC send data to STM32 by TCP connections. STM32 receives it and send it to CAN.Then,when STM32 receives datas from CAN ,it will send the datas to PC by all the TCP connections.Now,my idea is that typedef a structure,when STM32 received the data from PC,it will record the pcb,remote ip and remote port. And receiving data from CAN ,STM32 will send it through the recording data.The result is the data will be sent slowly when STM32 invokes the "tcp_write()" and "tcp_output"frequently.
So I wonder the solutions to implement multiple TCP connections.
#define TCP_WORKING 0xaa
#define TCP_FREE 0xa5
typedef struct Cmd_TCPData
{
unsigned char TCP_STATUS;
unsigned char cmd_flag;
unsigned short remote_port;
unsigned short data_len;
struct ip_addr remote_ip;
unsigned char *pData;
struct tcp_pcb *TCP_pcb;
}Cmd_TCPData;
Cmd_TCPData cmd_tcp;
Cmd_TCPData tcp_list[5];
static u8 TcpListNum;
void TCP_server_init(void)
{
struct tcp_pcb *pcb;
err_t err;
/*****************************************************/
pcb = tcp_new();
if (!pcb)
{
return ;
}
err = tcp_bind(pcb,IP_ADDR_ANY,devInfo.udpPort);
if(err != ERR_OK)
{
return ;
}
pcb = tcp_listen(pcb);
tcp_accept(pcb,tcp_server_accept);
}
static err_t tcp_server_accept(void *arg,struct tcp_pcb *pcb,err_t err)
{
tcp_setprio(pcb, TCP_PRIO_MIN);
tcp_recv(pcb,tcp_server_recv);
err = ERR_OK;
return err;
}
static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb,struct pbuf *p,err_t err)
{
struct pbuf *p_temp = p;
int nPos=0;
u8 searchtemp=0;
//TCP_pcbA=pcb;
while(tcp_list[searchtemp].TCP_STATUS==TCP_WORKING)
{
if(tcp_list[searchtemp].remote_ip.addr!= pcb->remote_ip.addr)
{
searchtemp++;
}
else
break;
if(searchtemp==5)
{
searchtemp=0;
break;
}
}
/******copy*******************/
tcp_list[searchtemp].TCP_pcb=pcb;
tcp_list[searchtemp].pData = TCPRecvBuf;
tcp_list[searchtemp].remote_port=pcb->remote_port;
tcp_list[searchtemp].remote_ip = pcb->remote_ip;
tcp_setprio(tcp_list[searchtemp].TCP_pcb, TCP_PRIO_MIN+searchtemp);
if(p_temp != NULL)
{
tcp_recved(pcb, p_temp->tot_len);
while(p_temp != NULL)
{
// tcp_write(pcb,p_temp->payload,p_temp->len,TCP_WRITE_FLAG_COPY);
// tcp_output(pcb);
memcpy(tcp_list[searchtemp].pData+nPos,p_temp->payload,p_temp->len);
nPos += p_temp->len;
p_temp = p_temp->next;
}
}
else
{
tcp_close(pcb);
}
tcp_list[searchtemp].data_len = nPos;
flash_led_tcp = 1;
tcp_list[searchtemp].TCP_STATUS= TCP_WORKING;
TcpListNum=searchtemp;
pbuf_free(p);
err = ERR_OK;
return err;
}
void send_tcp_data(u8_t *pPtr,u16_t data_len)
{
u8 x=0;
while(x<5)
{
if(tcp_list[x].TCP_STATUS==TCP_WORKING)
{
//TCP_pcbA->remote_port=tcp_list[x].remote_port;
//TCP_pcbA->remote_ip= tcp_list[x].remote_ip;
tcp_write(tcp_list[x].TCP_pcb,pPtr,data_len,TCP_WRITE_FLAG_COPY);
tcp_output(tcp_list[x].TCP_pcb);
}
OSTimeDlyHMSM(0, 0, 0, 250);//250ms
x++;
}
}

The tcp_server_accept() will contain the newly created connection. To this connection you can attach your context.
struct myclient_t
{
struct tcp_pcb *pcb;
/* all the variables uniqe for tracking this specific connection.. parser-state, receive/send buffers, statistics... */
int foo;
int bar;
};
static err_t tcp_server_accept(void *arg,struct tcp_pcb *pcb,err_t err)
{
err_t ret_err;
struct struct myclient_t *context = 0;
int i;
context = new_client();
if (!context )
{
return ERR_MEM;
}
context->pcb = pcb;
/* pass newly allocated es structure as argument to newpcb */
tcp_arg(newpcb, context); /* recv, sent, error and poll callbacks will have context their argument, which is uniqe for each connection */
/* initialize lwip tcp_recv callback function for newpcb */
tcp_recv(newpcb, tcp_server_recv
tcp_sent(newpcb, tcp_server_sent);
/* initialize lwip tcp_err callback function for newpcb */
tcp_err(newpcb, tcp_server_error);
/* initialize lwip tcp_poll callback function for newpcb */
tcp_poll(newpcb, tcp_server_poll, 1);
return ERR_OK;
}

Related

ESP8266 tcp recv returning errno 11 (EAGAIN) when handling large amounts of data

I am running ESP8266_RTOS_SDK_3.4 for an app that uses TCP to talk to a private port on a local server. In normal operation, it uploads large amounts of data to the server and receives acknowledgements that are usually less than 200 bytes: this always works fine. When I do an OTA update, where it's mainly receiving data, TCP recv fails on attempting to read the first block, and errno is set to 11 (EAGAIN). Even if I make the server send just 1024 bytes, the same thing happens.
This is the TCP connect and recv code:
bool net_tcp_connect (SENDER_DESTINATION * dest) {
struct sockaddr_in destAddr;
if (!find_host (dest->hostname)) {
return false;
}
memset(&destAddr, 0, sizeof(destAddr));
memcpy (&destAddr.sin_addr, findhost_ip (), sizeof (destAddr.sin_addr));
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons (dest->port);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
LOGEF("Create: errno %d", errno);
return false;
}
struct timeval tv;
tv.tv_sec = dest->timeout;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
if (connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)) != 0) {
LOGEF("Connect: %s %d errno %d", findhost_str (), dest->port, errno);
EVENT_HERE ( );
net_tcp_close ();
return false;
}
return true;
}
// --------------------------------------------------------------------------------------------
int net_tcp_recv (void * buffer, int max_length) {
if (sock < 0)
return false;
int bytes_received = recv (sock, buffer, max_length, 0);
if (bytes_received < 0) {
LOGEF("Receive: errno= %d", errno);
net_tcp_close ();
bytes_received = 0;
}
return bytes_received;
}
EAGAIN can be a sign of a receive timeout, but the timeout is set to 30 seconds and the server usually sends out the first 32k bytes in less than a second.
The ESP8266 code does run OK on some access points and, as far as I can tell, the same code on an ESP32 runs OK on all access points.
Any suggestions for why this might happen, or things that I could try changing in the code or the ESP setup to make it work reliably on any access point?

Linux: inter process communication by tcp 127.0.0.1 on the same node very slow

Tcp communication is very slow by 127.0.0.1 or eth IP(eg:10.10.253.12) on the same host.
server listen on 0.0.0.0:2000, client connect to 127.0.0.1:2000 or local eth ip:10.10.253.12:2000, CS transfer speed only 100KB per second.
Program written by C using libevent and Java using Netty have the same effect, program written as:
server accept connect, echo everything it received.
client sends arbitrary 128-byte data, when socket writable, send another 128-byte data; read and discard what it received.
This couple client\server program works fine if run on a different machine, the speed at 30MB per second.
But zeromq pair communication by 127.0.0.1 has no such issue.
Server side code is:
---start listener
struct evconnlistener *listener = evconnlistener_new_bind(leader,
listener_cb, NULL,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, s_backlog, &addr,
addrlen);
if (!listener) {
logit("Could not create a listener!");
return 1;
}
int fd = evconnlistener_get_fd(listener);
int keepAlive = 0; // 非0值,开启keepalive属性
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
do{
if (event_base_loop(leader, EVLOOP_NO_EXIT_ON_EMPTY) < 0){
break;
}
}while(!event_base_got_exit(leader));
---connect processing
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data) {
if (s_rcvbufsize > 0){
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&s_rcvbufsize, sizeof(s_rcvbufsize));
}
if (s_sndbufsize > 0){
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&s_sndbufsize, sizeof(s_sndbufsize));
}
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&s_tcpnodelay, sizeof(s_tcpnodelay));
int keepAlive = 0; // 非0值,开启keepalive属性
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
struct bufferevent *bev = bufferevent_socket_new(s_worker, fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
if (!bev) {
logit("Error constructing bufferevent!");
evutil_closesocket(fd);
return;
}
bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_READ);
}
---read\write processing
static void conn_writecb(struct bufferevent *bev, void *user_data) {
}
static void conn_readcb(struct bufferevent *bev, void *user_data) {
struct evbuffer *input = bufferevent_get_input(bev);
int len = evbuffer_get_length(input);
struct evbuffer *output = bufferevent_get_output(bev);
evbuffer_add_buffer(output, input);
}
Client side code is:
---init connection
struct bufferevent* bev= bufferevent_socket_new(s_event_base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
if (!bev){
return 1;
}
struct timeval tv;
tv.tv_sec = 30; //connect timeout
tv.tv_usec = 0;
bufferevent_set_timeouts(bev, NULL, &tv);
bufferevent_setcb(bev, NULL, NULL, connect_eventcb, (void*)s_event_base);
int flag = bufferevent_socket_connect(bev, &s_target_sockaddr, s_target_socklen);
if (-1 == flag ){
bufferevent_free(bev);
return 1;
}
---connected processing
static void connect_eventcb(struct bufferevent *bev, short events, void *user_data) {
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)){
bufferevent_free(bev);
}else if (events & BEV_EVENT_CONNECTED) {
int fd = bufferevent_getfd(bev);
if (s_sorcvbufsize > 0){
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&s_sorcvbufsize, sizeof(s_sorcvbufsize));
}
if (s_sosndbufsize > 0){
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&s_sosndbufsize, sizeof(s_sosndbufsize));
}
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&s_tcpnodelay, sizeof(s_tcpnodelay));
int keepAlive = 0; // 非0值,开启keepalive属性
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
bufferevent_setwatermark(bev, EV_WRITE, s_snd_wmark_l, s_snd_wmark_h);
bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_READ|EV_WRITE);
bufferevent_trigger(bev, EV_WRITE, BEV_TRIG_IGNORE_WATERMARKS|BEV_OPT_DEFER_CALLBACKS);
}
}
---read/write processing
static void conn_writecb(struct bufferevent *bev, void *user_data) {
struct evbuffer *output = bufferevent_get_output(bev);
for (int len = evbuffer_get_length(output); len < s_snd_wmark_h; len += s_sendsize){
if (0 != bufferevent_write(bev, s_send_buf, s_sendsize)){
break;
}
}
}
static void conn_readcb(struct bufferevent *bev, void *user_data) {
struct evbuffer *input = bufferevent_get_input(bev);
evbuffer_drain(input, 0x7FFFFFFF);
}
Tshark capture shows there is many KeepAliveReq no matter how SO_KEEPALIVE is setted:
Tshark capture result 1
Tshark capture result 2
I tested and resolved it now:
the main reason is send buffer size of the server side is two small(8K), then the recv size, which cause server send congest.
When I adjust both buffer size to 32K, the problem disappeared.

ESP32 TCP client

I want to set up TCP server on windows and TCP client on ESP32. Main idea is to send String to ESP32 change it and send it back to server, but I'm really new with all of this stuff and got stuck on setting up TCP client on ESP32. Examples or references would be really helpful.
int create_ipv4_socket()
{
struct addrinfo hints;
struct addrinfo *res;
struct in_addr *addr;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
int err = getaddrinfo(UDP_IPV4_ADDR, TCP_PORT, &hints, &res);
if(err != 0 || res == NULL) {
printf("DNS lookup failed err=%d res=%p\n", err, res);
return -1;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
printf("DNS lookup succeeded. IP=%s\n", inet_ntoa(*addr));
l_sock = socket(res->ai_family, res->ai_socktype, 0);
if(l_sock < 0) {
printf("... Failed to allocate socket.\n");
freeaddrinfo(res);
return -1;
}
struct timeval to;
to.tv_sec = 2;
to.tv_usec = 0;
setsockopt(l_sock,SOL_SOCKET,SO_SNDTIMEO,&to,sizeof(to));
if(connect(l_sock, res->ai_addr, res->ai_addrlen) != 0) {
printf("... socket connect failed errno=%d\n", errno);
close(l_sock);
freeaddrinfo(res);
return -1;
}
printf("... connected\n");
freeaddrinfo(res);
// All set, socket is configured for sending and receiving
return l_sock;
}
From this forum https://www.esp32.com/viewtopic.php?t=5965
How do you communicate with your ESP? if you communicate through UART, just send him AT command he need by writing on the UART port:
"AT+CIPSTATUS\r\n"
and then wait for his response.
If you are connected to your ESP32 directly with your computer, just use putty and directly send AT command to it.
A non exhaustive list of AT's command can be found here:
https://www.espressif.com/sites/default/files/documentation/esp32_at_instruction_set_and_examples_en.pdf

How can I use lwIP tcp/ip stack with microcontroller stm32f4 (client)

Core: Cortex-M4
Microcontroller: stm32f407 (stm32f4 discovery board)
IP Stack: lwIP 1.4.1
I am using this microcontroller to control an automate and I want to send some information to a separate web server via a HTTP request in the form of:
http://192.168.1.3/api/xdevices.json?SetR=01
lwIP has a http server for the microprocessor, but I'm after the opposite (microcontroller is the client).
I am not sure what i'm doing wrong but after TCP_Connect it always goes to tcp_error handler :
#include "stm32f4xx.h"
/* Include my libraries here */
#include "defines.h"
#include "tm_stm32f4_delay.h"
#include "tm_stm32f4_disco.h"
#include "tm_stm32f4_usart.h"
#include "tm_stm32f4_ethernet.h"
#include "tm_stm32f4_watchdog.h"
#include <stdio.h>
#include <stdlib.h>
#include <lwip/tcp.h>
#include <tcp.h>
uint32_t tcp_send_packet(void);
void tcpErrorHandler(void *arg, err_t err);
err_t tcpSendCallback(void *arg, struct tcp_pcb *tpcb,u16_t len);
err_t connectCallback(void *arg, struct tcp_pcb *tpcb, err_t err);
struct tcp_pcb *testpcb;
first Function is tcp_new :
void tcp_setup(void)
{
uint32_t data = 0xdeadbeef;
/* create an ip */
struct ip_addr ip;
IP4_ADDR(&ip,192,168,1,4); //IP of my PHP server
/* create the control block */
testpcb = tcp_new(); //testpcb is a global struct tcp_pcb
// as defined by lwIP
/* dummy data to pass to callbacks*/
tcp_arg(testpcb, &data);
/* register callbacks with the pcb */
// tcp_recv(testpcb, tcpRecvCallback);
tcp_sent(testpcb, tcpSendCallback);
tcp_err(testpcb, tcpErrorHandler);
/* now connect */
tcp_connect(testpcb, &ip, 21, connectCallback);
TM_DISCO_LedOn(LED_ORANGE);
}
My Callbacks :
void tcpErrorHandler(void *arg, err_t err){
TM_DISCO_LedOn(LED_BLUE);
}
err_t tcpSendCallback(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
TM_DISCO_LedOn(LED_RED);
}
err_t connectCallback(void *arg, struct tcp_pcb *tpcb, err_t err)
{
TM_DISCO_LedOn(LED_RED);
tcp_send_packet();
return 0;
}
my header :
uint32_t tcp_send_packet(void)
{
char *string = "SetR=01\r\n\r\n ";
uint32_t len = strlen(string);
/* push to buffer */
tcp_write(testpcb, string, strlen(string), TCP_WRITE_FLAG_COPY);
/* now send */
tcp_output(testpcb);
return 0;
}
void lwip_init();
Main function :
int main(void) {
/* Initialize system */
SystemInit();
lwip_init();
/* Initialize delay */
TM_DELAY_Init();
/* Initialize leds on board */
TM_DISCO_LedInit();
/* Initialize button */
TM_DISCO_ButtonInit();
while(1) {
tcp_setup();
} }
Clearly i'm forgetting something i just don't know what it is .( i'm using Keil arm)
thank you
Init LwIP with lwip_init
Call tcp_setup outside while loop only once not in while loop to setup only one TCP connection, not unlimited
In while loop, process LwIP incoming data periodically. Since you are using my (TM Tilen Majerle) ethernet wrapper for STM32F4, you should add these lines inside your while loop
/* Check if any packet received */
if (LwIP_CheckFrameReceived()) {
/* Process received ethernet packet */
LwIP_Pkt_Handle();
}
/* Handle periodic timers for LwIP */
LwIP_Periodic_Handle(EthernetLocalTime);
Or call TM_ETHERNET_Update function from your library. Your choice, it works the same.
In your case:
int main() {
....
lwip_init();
tcp_setup();
while (1) {
TM_ETHERNET_Update();
}
}

Arduino turn char into a string

I am trying to turn a char into a string so I can extract the values I am interested in, however it just appears empty.
The variable I am interested in is content.
I am performing a get and it returns a JSON object. And want to extract the sunrise and sunset values.
#include <SPI.h>
#include <Ethernet2.h>
#include <String.h>
#include <stdlib.h>
EthernetClient client;
const char* server = "api.sunrise-sunset.org"; // server's address
const char* resource = "/json?lat=53.440&lng=0.200&date=today"; // http resource
const unsigned long BAUD_RATE = 9600; // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response
// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
initSerial();
initEthernet();
}
// ARDUINO entry point #2: runs over and over again forever
void loop() {
if (connect(server)) {
if (sendRequest(server, resource) && skipResponseHeaders()) {
char response[MAX_CONTENT_SIZE];
String str(response);
Serial.println(str);
char* field;
char* sunset;
char* sunrise;
field = strtok(response,"{,");
while (field != NULL)
{
field = strtok (NULL, ",}");
if(field != NULL)
{
if(strstr(field, "sunrise") != NULL)
{
int length = strlen(field);
sunrise = new char[length + 1];
strncpy(sunrise, field, length + 1); // +1 to copy a terminating null as well
}
if(strstr(field, "sunset") != NULL)
{
int length = strlen(field);
sunset = new char[length + 1];
strncpy(sunset, field, length + 1); // +1 to copy a terminating null as well
}
}
}
//Serial.println("SUNRISE DATA: %s\n\n", sunrise);
//Serial.println("SUNSET DATA: %s\n\n", sunset);
free(sunrise); // do not forget to free the memory if not needed anymore
free(sunset); // do not forget to free the memory if not needed anymore
}
disconnect();
}
wait();
}
// Initialize Serial port
void initSerial() {
Serial.begin(BAUD_RATE);
while (!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
}
// Initialize Ethernet library
void initEthernet() {
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = { 192,168,0,202 };
if (!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
delay(1000);
}
// Open connection to the HTTP server
bool connect(const char* hostName) {
Serial.print("Connect to ");
Serial.println(hostName);
bool ok = client.connect(hostName, 80);
Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}
// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
Serial.print("GET ");
Serial.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
return true;
}
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "\r\n\r\n";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if (!ok) {
Serial.println("No response or invalid response!");
}
return ok;
}
void disconnect() {
Serial.println("Disconnect");
client.stop();
}
// Pause for a 1 minute
void wait() {
Serial.println("Wait 60 seconds");
delay(60000);
}
I think there is a misunderstanding from your side. Certainly you want to process the response of the server and according to your code, this is char response[MAX_CONTENT_SIZE] where the response is stored.
Now this already is a string, more or less. An array of characters, chars. Definiton from here.
Strings are actually one-dimensional array of characters terminated by a null character '\0'. Thus a null-terminated string contains the characters that comprise the string followed by a null.
You can extract the relevant parts from it straight away.
Your response should look like something like this, according to sunrise-sunset.org/api. Note that I just copied the data into an array for testing purposes.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_CONTENT_SIZE 512
char response[MAX_CONTENT_SIZE] = \
"{\
\"results\":\
{\
\"sunrise\":\"7:27:02 AM\",\
\"sunset\":\"5:05:55 PM\",\
\"solar_noon\":\"12:16:28 PM\",\
\"day_length\":\"9:38:53\",\
\"civil_twilight_begin\":\"6:58:14 AM\",\
\"civil_twilight_end\":\"5:34:43 PM\",\
\"nautical_twilight_begin\":\"6:25:47 AM\",\
\"nautical_twilight_end\":\"6:07:10 PM\",\
\"astronomical_twilight_begin\":\"5:54:14 AM\",\
\"astronomical_twilight_end\":\"6:38:43 PM\"\
},\
\"status\":\"OK\"\
}";
You can easily process it using strtok function from string.h. Using a {, delimiter first will separate "result":{ from "sunrise .... Then you can use a }, delimiter.
With strstr you can check for "sunrise" and "sunset" field, and if you find them you can copy their value into a new string with strncpy.
int main()
{
char* field;
char* sunset;
char* sunrise;
field = strtok(response,"{,");
while (field != NULL)
{
field = strtok (NULL, ",}");
if(field != NULL)
{
if(strstr(field, "sunrise") != NULL)
{
int length = strlen(field);
sunrise = malloc(length * sizeof(char) + 1); // +1 for terminating null character '\0'
strncpy(sunrise, field, length + 1); // +1 to copy a terminating null as well
}
if(strstr(field, "sunset") != NULL)
{
int length = strlen(field);
sunset = malloc(length * sizeof(char) + 1); // +1 for terminating null character '\0'
strncpy(sunset, field, length + 1); // +1 to copy a terminating null as well
}
}
}
printf("SUNRISE DATA: %s\n\n", sunrise);
printf("SUNSET DATA: %s\n\n", sunset);
free(sunrise); // do not forget to free the memory if not needed anymore
free(sunset); // do not forget to free the memory if not needed anymore
return 0;
}
The output of this program is:
SUNRISE DATA: "sunrise":"7:27:02 AM"
SUNSET DATA: "sunset":"5:05:55 PM"
You can further process these strings with strtok again if you like. This is just an example code, you can use it to implement your solution.

Resources