Simple working of Imgui, Implot and UDP Socket
The Example ImGUI_Implot_UDPSocket github link, Create a simple working for ImGUI and Implot with VisualStudio 22 to show the working of UDP socket.
* The example shows integrating Imgui with Implot with glfw.
* The example shows UDP socket send and receive through winsock2.
* The example shows the real time plot of value.

ImGui (Immediate Mode GUI) is a lightweight, fast, and easy-to-integrate graphical user interface library designed primarily for real-time applications like game engines, simulations, and tools. Unlike traditional GUIs that store the state of widgets, ImGui works in “immediate mode,” where the UI is fully reconstructed every frame based on the current state. This makes it highly efficient and flexible for dynamic UIs, as developers can modify the interface directly in the render loop. ImGui is widely used for debugging interfaces, editor tools, and quick prototyping because of its simple API, minimal setup, and real-time responsiveness.
A UDP socket is a communication endpoint that uses the User Datagram Protocol (UDP) for transmitting data over a network. Unlike TCP, UDP is a connectionless protocol, meaning it sends messages, called datagrams, without establishing a reliable connection between sender and receiver. This makes UDP lightweight and faster but less reliable, as it doesn’t guarantee delivery, ordering, or error-checking of packets. UDP sockets are commonly used in applications where speed is critical and occasional data loss is acceptable, such as in real-time video streaming, online gaming, or VoIP (Voice over IP).
Sending Data Section
Send Network part:
// Network.h header file for C++ UDP
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <system_error>
#include <string>
#include <iostream>
#include <winsock2.h>
#pragma once
#pragma comment (lib, "ws2_32")
class WSASession
{
public:
WSASession()
{
int ret = WSAStartup(MAKEWORD(2, 2), &data);
if (ret != 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "WSAStartup Failed");
}
~WSASession()
{
WSACleanup();
}
private:
WSAData data;
};
class UDPSocket
{
public:
UDPSocket()
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
throw std::system_error(WSAGetLastError(), std::system_category(), "Error opening socket");
}
~UDPSocket()
{
closesocket(sock);
}
void SendTo(const std::string& address, unsigned short port, const char* buffer, int len, int flags = 0)
{
sockaddr_in add;
add.sin_family = AF_INET;
add.sin_addr.s_addr = inet_addr(address.c_str());
//add.sin_addr.s_addr = inet_pton(AF_INET, "127.0.0.1", address.c_str());
add.sin_port = htons(port);
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR*>(&add), sizeof(add));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "sendto failed");
}
void SendTo(sockaddr_in& address, const char* buffer, int len, int flags = 0)
{
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR*>(&address), sizeof(address));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "sendto failed");
}
sockaddr_in RecvFrom(char* buffer, int len, int flags = 0)
{
sockaddr_in from;
int size = sizeof(from);
int ret = recvfrom(sock, buffer, len, flags, reinterpret_cast<SOCKADDR*>(&from), &size);
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "recvfrom failed");
// make the buffer zero terminated
buffer[ret] = 0;
return from;
}
void Bind(unsigned short port)
{
sockaddr_in add;
add.sin_family = AF_INET;
add.sin_addr.s_addr = htonl(INADDR_ANY);
add.sin_port = htons(port);
int ret = bind(sock, reinterpret_cast<SOCKADDR*>(&add), sizeof(add));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "Bind failed");
}
private:
SOCKET sock;
};
Sending Main part:
// C++ UDP Transmitter
#include "Network.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#pragma once
int main()
{
std::string IP = "127.0.0.1";
int PORT = 8888;
try
{
WSASession Session;
UDPSocket Socket;
std::string data = "hello world";
char buffer[100];
// create a clock and start timer
clock_t TimeZero = clock(); //Start timer
std::cout << "Start time: " << TimeZero << std::endl;
double deltaTime = 0;
double hz_value = 10;
double reset_time = 1000 / hz_value;
// generate random seed using time
srand(time(0));
while (1)
{
// get delta time in milliseconds
deltaTime = (clock() - TimeZero);
// compare if delta time is 2 or more seconds
if (deltaTime > reset_time) {
struct tm newtime;
time_t now = time(0);
localtime_s(&newtime, &now);
//std::cout << "Current local time : " << newtime.tm_hour << ":" << newtime.tm_min << ":" << newtime.tm_sec <<std::endl;
// generate new random number
int i = rand() % 100 + 1;
//std::cout << ": New random : " << i << "\n";
data = std::to_string(newtime.tm_hour) +":" + std::to_string(newtime.tm_min) + ":" + std::to_string(newtime.tm_sec) + " " + std::to_string(i);
std::cout << data << std::endl;
Socket.SendTo(IP, PORT, data.c_str(), data.size());
//reset the clock timers
TimeZero = clock();
}
}
}
catch (std::exception& ex)
{
std::cout << ex.what();
}
}

Explanation:
Here the UDP network socket is created using winsock2. Then a random value is generated with a time stamp of the system and sent through the created socket.
Receive Data Section:
Receive Network part:
// Network.h
#include <iostream>
#include <winsock2.h>
//#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
class UDPHandler {
private:
SOCKET sockfd;
struct sockaddr_in serverAddr, clientAddr;
int addrLen;
char buffer[1024];
public:
UDPHandler(int port) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed" << std::endl;
exit(EXIT_FAILURE);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET) {
std::cerr << "Socket creation failed" << std::endl;
WSACleanup();
exit(EXIT_FAILURE);
}
// Set socket options using setsockopt()
int timeout = 10; // 5 seconds
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
std::cerr << "setsockopt failed" << std::endl;
closesocket(sockfd);
WSACleanup();
exit(EXIT_FAILURE);
}
memset(&serverAddr, 0, sizeof(serverAddr));
memset(&clientAddr, 0, sizeof(clientAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Bind failed" << std::endl;
closesocket(sockfd);
WSACleanup();
exit(EXIT_FAILURE);
}
addrLen = sizeof(clientAddr);
}
std::string receiveData() {
int n = recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr *)&clientAddr, &addrLen);
if (n == SOCKET_ERROR) {
std::cerr << "Receive failed" << std::endl;
return "NILL";
}
buffer[n] = '\0';
return std::string(buffer);
}
void sendData(const std::string &data) {
sendto(sockfd, data.c_str(), data.length(), 0, (struct sockaddr *)&clientAddr, addrLen);
}
~UDPHandler() {
closesocket(sockfd);
WSACleanup();
}
};
Receive Main part:
//main.cpp
std::vector<std::string> split(std::string s, std::string delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
UDPHandler udpHandler(8888); // Initialize UDPHandler with the desired port
// assign graph
static float xs1[10000], ys1[10000];
int gcount1 = 0;
// Main loop
#ifdef __EMSCRIPTEN__
// For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
// You may manually call LoadIniSettingsFromMemory() to load settings from your own storage.
io.IniFilename = nullptr;
EMSCRIPTEN_MAINLOOP_BEGIN
#else
while (!glfwWindowShouldClose(window))
#endif
{
glfwPollEvents();
if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0)
{
ImGui_ImplGlfw_Sleep(10);
continue;
}
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
{
static float f = 0.0f;
//static int counter = 0;
ImGui::Begin("Main Window"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("List of Graphs"); // Display some text (you can use a format strings too)
ImGui::Checkbox("show graph", &show_graph); // Edit bools storing our window open/close state
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
if(show_graph)
{
ImGui::Begin("graph");
// Receive UDP data
std::string receivedData = udpHandler.receiveData();
// Process the data (for simplicity, we'll just print it here)
std::cout << "Received: " << receivedData << std::endl;
std::string delimiter = " ";
std::vector<std::string> v = split(receivedData, delimiter);
for (auto i : v) std::cout << i << std::endl;
if (v[0] != "NILL")
{
xs1[gcount1] = gcount1;
ys1[gcount1] = std::stof(v[1]);
gcount1++;
}
if (ImPlot::BeginPlot("Line Plots")) {
ImPlot::SetupAxes("x", "y");
ImPlot::PlotLine("f(x)", xs1, ys1, gcount1);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
//ImPlot::PlotLine("g(x)", xs2, ys2, 20, ImPlotLineFlags_Segments);
ImPlot::EndPlot();
}
ImGui::End();
}
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_MAINLOOP_END;
#endif
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
Explanation:
Here the UDP network socket for receiving is created using winsock2. Then the data is extracted and send to the implot data. Once the data is received the graph is updated accordingly.
Leave a Reply