Skip to content

Instantly share code, notes, and snippets.

@vlaleli
Last active February 28, 2026 06:38
Show Gist options
  • Select an option

  • Save vlaleli/ef0ad9442cdd702faf2ac26b03dcdbbc to your computer and use it in GitHub Desktop.

Select an option

Save vlaleli/ef0ad9442cdd702faf2ac26b03dcdbbc to your computer and use it in GitHub Desktop.
socket server/client
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <thread>
static const int SERVER_PORT = 5555;
static void ReaderThread(int fd) {
char buf[2048];
while (true) {
ssize_t n = recv(fd, buf, sizeof(buf) - 1, 0);
if (n > 0) {
buf[n] = 0;
std::cout << buf;
std::cout.flush();
} else {
break;
}
}
}
int main() {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
std::cerr << "socket failed\n";
return 1;
}
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) {
std::cerr << "connect failed\n";
close(fd);
return 1;
}
std::thread t(ReaderThread, fd);
std::cout << "TIME\nDATE\nWEATHER Odesa\nEUR UAH\nBTC USD\n";
std::string line;
while (std::getline(std::cin, line)) {
line += "\n";
send(fd, line.c_str(), line.size(), 0);
}
shutdown(fd, SHUT_RDWR);
close(fd);
t.join();
return 0;
}
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <cctype>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
#include <curl/curl.h>
static const int SERVER_PORT = 5555;
struct ClientState {
int fd;
std::string inbuf;
std::mutex send_mtx;
};
static size_t CurlWriteCb(void* contents, size_t size, size_t nmemb, void* userp) {
size_t total = size * nmemb;
std::string* s = (std::string*)userp;
s->append((const char*)contents, total);
return total;
}
static bool HttpGet(const std::string& url, std::string& out_body) {
CURL* curl = curl_easy_init();
if (!curl) return false;
out_body.clear();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out_body);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
CURLcode res = curl_easy_perform(curl);
long code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
curl_easy_cleanup(curl);
return (res == CURLE_OK && code >= 200 && code < 300);
}
static bool JsonFindNumber(const std::string& json, const std::string& key, double& out) {
std::string pat = "\"" + key + "\":";
size_t p = json.find(pat);
if (p == std::string::npos) return false;
p += pat.size();
while (p < json.size() && (json[p] == ' ' || json[p] == '\n' || json[p] == '\r' || json[p] == '\t')) p++;
size_t e = p;
while (e < json.size() && (std::isdigit((unsigned char)json[e]) || json[e] == '-' || json[e] == '.' || json[e] == 'e' || json[e] == 'E' || json[e] == '+')) e++;
if (e == p) return false;
out = std::stod(json.substr(p, e - p));
return true;
}
static void SendLine(ClientState* c, const std::string& line) {
std::lock_guard<std::mutex> lk(c->send_mtx);
std::string msg = line + "\n";
const char* buf = msg.c_str();
size_t left = msg.size();
while (left > 0) {
ssize_t n = send(c->fd, buf, left, 0);
if (n > 0) {
buf += n;
left -= (size_t)n;
} else {
break;
}
}
}
static std::string NowTimeStr() {
std::time_t t = std::time(nullptr);
std::tm tm{};
localtime_r(&t, &tm);
std::ostringstream oss;
oss << std::put_time(&tm, "%H:%M:%S");
return oss.str();
}
static std::string NowDateStr() {
std::time_t t = std::time(nullptr);
std::tm tm{};
localtime_r(&t, &tm);
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%d");
return oss.str();
}
static void HandleTIME(ClientState* c) {
SendLine(c, "OK TIME " + NowTimeStr());
}
static void HandleDATE(ClientState* c) {
SendLine(c, "OK DATE " + NowDateStr());
}
static void HandleEUR(ClientState* c, const std::string& to) {
std::string url = "https://api.frankfurter.dev/v1/latest?base=EUR&symbols=" + to;
std::string body;
if (!HttpGet(url, body)) { SendLine(c, "ERR EUR fetch_failed"); return; }
double rate = 0.0;
if (!JsonFindNumber(body, to, rate)) { SendLine(c, "ERR EUR parse_failed"); return; }
SendLine(c, "OK EUR " + to + " " + std::to_string(rate));
}
static void HandleBTC(ClientState* c, std::string to) {
for (auto& ch : to) ch = (char)std::tolower((unsigned char)ch);
std::string url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=" + to;
std::string body;
if (!HttpGet(url, body)) { SendLine(c, "ERR BTC fetch_failed"); return; }
double price = 0.0;
if (!JsonFindNumber(body, to, price)) { SendLine(c, "ERR BTC parse_failed"); return; }
SendLine(c, "OK BTC " + to + " " + std::to_string(price));
}
static void HandleWEATHER(ClientState* c, std::string city) {
std::string q = city;
for (auto& ch : q) if (ch == ' ') ch = '+';
std::string geoUrl = "https://geocoding-api.open-meteo.com/v1/search?name=" + q + "&count=1&language=en&format=json";
std::string geoBody;
if (!HttpGet(geoUrl, geoBody)) { SendLine(c, "ERR WEATHER geocode_failed"); return; }
double lat = 0.0, lon = 0.0;
if (!JsonFindNumber(geoBody, "latitude", lat) || !JsonFindNumber(geoBody, "longitude", lon)) {
SendLine(c, "ERR WEATHER city_not_found");
return;
}
std::ostringstream wurl;
wurl << "https://api.open-meteo.com/v1/forecast?latitude=" << lat << "&longitude=" << lon << "&current_weather=true";
std::string wBody;
if (!HttpGet(wurl.str(), wBody)) { SendLine(c, "ERR WEATHER forecast_failed"); return; }
double temp = 0.0, wcode = 0.0;
if (!JsonFindNumber(wBody, "temperature", temp) || !JsonFindNumber(wBody, "weathercode", wcode)) {
SendLine(c, "ERR WEATHER parse_failed");
return;
}
std::ostringstream out;
out << "OK WEATHER " << city << " " << temp << "C code=" << (int)wcode;
SendLine(c, out.str());
}
static void DispatchCommand(ClientState* c, const std::string& line) {
std::istringstream iss(line);
std::string cmd;
iss >> cmd;
if (cmd.empty()) return;
if (cmd == "TIME") { std::thread(HandleTIME, c).detach(); return; }
if (cmd == "DATE") { std::thread(HandleDATE, c).detach(); return; }
if (cmd == "WEATHER") {
std::string city;
std::getline(iss, city);
if (!city.empty() && city[0] == ' ') city.erase(0, 1);
if (city.empty()) { SendLine(c, "ERR WEATHER need_city"); return; }
std::thread(HandleWEATHER, c, city).detach();
return;
}
if (cmd == "EUR") {
std::string to;
iss >> to;
if (to.empty()) { SendLine(c, "ERR EUR need_currency"); return; }
std::thread(HandleEUR, c, to).detach();
return;
}
if (cmd == "BTC") {
std::string to;
iss >> to;
if (to.empty()) { SendLine(c, "ERR BTC need_currency"); return; }
std::thread(HandleBTC, c, to).detach();
return;
}
SendLine(c, "ERR unknown_command");
}
static bool SetNonBlocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return false;
return (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
}
int main() {
signal(SIGPIPE, SIG_IGN);
curl_global_init(CURL_GLOBAL_DEFAULT);
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) { std::cerr << "socket failed\n"; return 1; }
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
if (bind(listen_fd, (sockaddr*)&addr, sizeof(addr)) < 0) { close(listen_fd); return 1; }
if (listen(listen_fd, 16) < 0) { close(listen_fd); return 1; }
SetNonBlocking(listen_fd);
std::vector<ClientState*> clients;
std::cout << "Server started on port " << SERVER_PORT << "\n";
while (true) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(listen_fd, &rfds);
int maxfd = listen_fd;
for (auto* c : clients) {
FD_SET(c->fd, &rfds);
if (c->fd > maxfd) maxfd = c->fd;
}
timeval tv{};
tv.tv_sec = 1;
tv.tv_usec = 0;
int ready = select(maxfd + 1, &rfds, nullptr, nullptr, &tv);
if (ready < 0) continue;
if (FD_ISSET(listen_fd, &rfds)) {
sockaddr_in cli{};
socklen_t len = sizeof(cli);
int cfd = accept(listen_fd, (sockaddr*)&cli, &len);
if (cfd >= 0) {
SetNonBlocking(cfd);
auto* cs = new ClientState{cfd, "", {}};
clients.push_back(cs);
SendLine(cs, "OK connected");
}
}
for (size_t i = 0; i < clients.size();) {
ClientState* c = clients[i];
bool remove = false;
if (FD_ISSET(c->fd, &rfds)) {
char buf[2048];
while (true) {
ssize_t n = recv(c->fd, buf, sizeof(buf), 0);
if (n > 0) {
c->inbuf.append(buf, (size_t)n);
while (true) {
size_t pos = c->inbuf.find('\n');
if (pos == std::string::npos) break;
std::string line = c->inbuf.substr(0, pos);
c->inbuf.erase(0, pos + 1);
if (!line.empty() && line.back() == '\r') line.pop_back();
DispatchCommand(c, line);
}
} else if (n == 0) {
remove = true;
break;
} else {
if (errno == EWOULDBLOCK || errno == EAGAIN) break;
remove = true;
break;
}
}
}
if (remove) {
close(c->fd);
delete c;
clients.erase(clients.begin() + (long)i);
} else {
i++;
}
}
}
curl_global_cleanup();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment