Example Code for MemCached in C - c

I am looking for some sample C code for using memcache to set a value
Connecting to Server/Port
using multiple memcache_set
Close
I have the app running in PHP in 5 lines of code but can not find any good memcache samples in C which I need to port to.

This is a great memcached sample in C
#include <libmemcached/memcached.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
//memcached_servers_parse (char *server_strings);
memcached_server_st *servers = NULL;
memcached_st *memc;
memcached_return rc;
char *key = "keystring";
char *value = "keyvalue";
char *retrieved_value;
size_t value_length;
uint32_t flags;
memc = memcached_create(NULL);
servers = memcached_server_list_append(servers, "localhost", 11211, &rc);
rc = memcached_server_push(memc, servers);
if (rc == MEMCACHED_SUCCESS)
fprintf(stderr, "Added server successfully\n");
else
fprintf(stderr, "Couldn't add server: %s\n", memcached_strerror(memc, rc));
rc = memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0);
if (rc == MEMCACHED_SUCCESS)
fprintf(stderr, "Key stored successfully\n");
else
fprintf(stderr, "Couldn't store key: %s\n", memcached_strerror(memc, rc));
retrieved_value = memcached_get(memc, key, strlen(key), &value_length, &flags, &rc);
printf("Yay!\n");
if (rc == MEMCACHED_SUCCESS) {
fprintf(stderr, "Key retrieved successfully\n");
printf("The key '%s' returned value '%s'.\n", key, retrieved_value);
free(retrieved_value);
}
else
fprintf(stderr, "Couldn't retrieve key: %s\n", memcached_strerror(memc, rc));
return 0;
}

Here is a slightly more complete answer, which also shows how to get and delete from a memcached server. The code is technically in C++, but doesn't use any features that would be unfamiliar to most C programmers.
To compile: g++ sample.cc -o sample -ggdb -O3 -lmemcached
To run: ./sample -s localhost -p 11211
The functions whose names begin with mcd_ show the basics of inserting, deleting, and getting, as well as connecting and disconnecting from memcached. The remaining code makes use of those functions to insert 50 key/value pairs, verify they all are in the server, remove half the pairs, and then verify that the right keys remain / are gone.
#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <libmemcached/memcached.h>
// NB: I know that `using namespace std` at global scope is bad form, and that
// global variables are bad form. However, they help keep this answer under
// 200 lines.
using namespace std;
/// The connection to memcached
memcached_st *mcd;
/// A global set of key/value pairs that we manufacture for the sake of this
/// example
vector<pair<string, string>> kv_pairs;
/// Put a key/value pair into memcached with expiration 0, no special flags
bool mcd_set(const string &key, const string &val) {
auto rc = memcached_set(mcd, key.c_str(), key.length(), val.c_str(),
val.length(), (time_t)0, (uint32_t)0);
if (rc == MEMCACHED_SUCCESS)
return true;
cout << "Error in mcd_set(): " << memcached_strerror(mcd, rc) << endl;
return false;
}
/// Delete a key/value pair from memcached. return true on success
/// NB: `(time_t)0` is an expiration of `0`, i.e., immediately
bool mcd_delete(const string &key) {
auto rc = memcached_delete(mcd, key.c_str(), key.length(), (time_t)0);
if (rc == MEMCACHED_SUCCESS)
return true;
cout << "Error in mcd_delete(): " << memcached_strerror(mcd, rc) << endl;
return false;
}
/// Get a value from the kv store, using its key to do the lookup. return
/// true on success. On success, the by-ref out parameter `val` will be set.
bool mcd_get(const string &key, string &val) {
memcached_return rc;
size_t len;
uint32_t flags = 0;
char *res = memcached_get(mcd, key.c_str(), key.length(), &len, &flags, &rc);
if (rc == MEMCACHED_SUCCESS) {
val = string(res, len);
free(res);
return true;
}
// NB: skip next line, because we don't want error messages on a failed get:
//
// cout << "Error in mcd_get(): " << memcached_strerror(mcd, rc) << endl;
return false;
}
/// Connect to a single memcached server on the provided port
bool mcd_connect(const string &servername, const int port) {
mcd = memcached_create(nullptr);
memcached_return rc;
memcached_server_st *servers = nullptr;
servers =
memcached_server_list_append(servers, servername.c_str(), port, &rc);
rc = memcached_server_push(mcd, servers);
if (rc == MEMCACHED_SUCCESS) {
cout << " Successfully connected to " << servername << ":" << port << endl;
return true;
}
cout << "Error in mcd_connect(): " << memcached_strerror(mcd, rc) << endl;
return false;
}
/// Close the connection to memcached
void mcd_shutdown() {
memcached_free(mcd);
cout << " Successfully disconnected\n";
}
/// Create a bunch of key/value pairs
void build_kv_pairs(int howmany) {
for (int i = 0; i < howmany; ++i) {
string key = "key" + to_string(i) + "_______";
string val = "val" + to_string(i);
for (int i = 0; i < 100; ++i)
val += ("_" + to_string(i));
kv_pairs.push_back({key, val});
}
}
/// insert a bunch of k/v pairs into memcached
bool put_kv_pairs(int howmany) {
for (int i = 0; i < howmany; ++i) {
if (!mcd_set(kv_pairs[i].first, kv_pairs[i].second)) {
cout << "Error inserting key `" << kv_pairs[i].first << "`\n";
return false;
}
}
cout << " put_kv_pairs(" << howmany << ") completed successfully\n";
return true;
}
/// Remove a sequence of keys from memcached
///
/// NB: Here and below, we use first/last/stride so that we can vary wich
/// key/value pairs are operated on
bool delete_kv_pairs(int first, int last, int stride) {
for (int i = first; i <= last; i += stride) {
if (!mcd_delete(kv_pairs[i].first)) {
cout << "Error removing key `" << kv_pairs[i].first << "`\n";
return false;
}
}
cout << " delete_kv_pairs(" << first << ", " << last << ", " << stride
<< ") completed successfully\n";
return true;
}
/// Verify that a sequence of keys is in memcached, with the right expected
/// values
bool check_present_pairs(int first, int last, int stride) {
for (int i = first; i <= last; i += stride) {
string value;
if (!mcd_get(kv_pairs[i].first, value)) {
cout << "Error getting key `" << kv_pairs[i].first
<< "`: key not found\n";
return false;
}
if (value != kv_pairs[i].second) {
cout << "Value error while getting key `" << kv_pairs[i].first << "`\n";
cout << " Expected: `" << kv_pairs[i].second << "`\n";
cout << " Found: `" << value << "`\n";
return false;
}
}
cout << " check_present_pairs(" << first << ", " << last << ", " << stride
<< ") completed successfully\n";
return true;
}
/// Verify that a sequence of keys is *not* in memcached
bool check_missing_pairs(int first, int last, int stride) {
for (int i = first; i <= last; i += stride) {
string value;
if (mcd_get(kv_pairs[i].first, value)) {
cout << "Error getting key `" << kv_pairs[i].first
<< "`: key unexpectedly found\n";
return false;
}
}
cout << " check_missing_pairs(" << first << ", " << last << ", " << stride
<< ") completed successfully\n";
return true;
}
int main(int argc, char **argv) {
// Parse args to get server name (-s) and port (-p)
string servername = "";
int port;
long opt;
while ((opt = getopt(argc, argv, "s:p:")) != -1) {
switch (opt) {
case 's':
servername = string(optarg);
break;
case 'p':
port = atoi(optarg);
break;
}
}
// Create a bunch of key/value pairs to use for the experiments
int howmany = 50;
build_kv_pairs(howmany);
// Connect to memcached
mcd_connect(servername, port);
// insert all the pairs, make sure they are all present
put_kv_pairs(howmany);
check_present_pairs(0, howmany - 1, 1);
// Delete the even pairs
delete_kv_pairs(0, howmany - 2, 2);
// ensure the odd pairs are present
check_present_pairs(1, howmany - 1, 2);
// ensure the even pairs are not present
check_missing_pairs(0, howmany, 2);
mcd_shutdown();
}
The code should produce output like the following:
Successfully connected to localhost:11211
put_kv_pairs(50) completed successfully
check_present_pairs(0, 49, 1) completed successfully
delete_kv_pairs(0, 48, 2) completed successfully
check_present_pairs(1, 49, 2) completed successfully
check_missing_pairs(0, 50, 2) completed successfully
Successfully disconnected

Related

Does TUN interface support recvmmsg/sendmmsg to receive/send multiple messages in a single system call

sendmmsg/recvmmsg provide the option to send and receive multiple packets on socket in a single system call. Are these operations supported for TUN adaptor on Linux using C socket API.
Here is the sample code I tried but get errno=Socket operation on non-socket
struct mmsghdr hdrs[ARRAY_SIZE];
unsigned char data[ARRAY_SIZE][BUFF_SIZE];
struct iovec iovecs[ARRAY_SIZE];
memset(hdrs, 0, sizeof(hdrs));
for (int i = 0; i < ARRAY_SIZE; i++)
{
iovecs[i].iov_base = data[i];
iovecs[i].iov_len = BUFF_SIZE;
hdrs[i].msg_hdr.msg_iov = &iovecs[i];
hdrs[i].msg_hdr.msg_iovlen = 1;
}
while (true)
{
LOG_DEBUG(log__) << "blocking to read on fd=" << fd;
int retVal = recvmmsg(fd, hdrs, ARRAY_SIZE, 0, NULL);
LOG_DEBUG(log__) << "retVal=" << retVal;
if (retVal < 0)
{
LOG_ERROR(log__) << "failed in recvmmsg, retVal=" << retVal << ", errno=" << strerror(errno);
continue;
}
LOG_DEBUG(log__) << "read " << retVal << " messages";
for (int i = 0; i < retVal; i++)
{
LOG_DEBUG(log__) << "read data of length " << hdrs[i].msg_len;
}
}

I want to ask about the use of the kea dhcp server, I hope someone can help me

I want to modify the dhcp4 source code to notify the ddns server to set the dynamic domain name when assigning the lease, but I added the nanomsg statement in dhcp4_srv.cc. When my nanomsg performs shutdown or close, the dhcp4 service will automatically close. This is why there is no other way to implement dynamic domain names (my dynamic domain name mainly sends the field set by the foreground and the mac address and IP address to the ddns server, or it may be the login account of the foreground).
Someone can help me? thank you very much.
if (lease) {
// We have a lease! Let's set it in the packet and send it back to
// the client.
// 我们有租约! 让我们在数据包中进行设置,然后将其发送回客户端。
if (fake_allocation) {
//租约建议
LOG_INFO(lease4_logger, DHCP4_LEASE_ADVERT)
.arg(query->getLabel())
.arg(lease->addr_.toText());
} else {
//成功授予租约
LOG_INFO(lease4_logger, DHCP4_LEASE_ALLOC)
.arg(query->getLabel())
.arg(lease->addr_.toText())
.arg(lease->valid_lft_);
int rc = 0;
int pair_socket = 0;
int str_len = 0;
char buf[256] = { 0 };
char buf1[256] = { 0 };
int timeo = 5000;
//计算长度
str_len = strlen(HELLOWORLD);
//初始化socket
pair_socket = nn_socket(1, NN_PAIR);
if (pair_socket == -1) {
printf("nn_socket failed! error: %s.\n", nn_err_strerror(errno));
//system("pause");
nn_err_abort();
//return 0;
}
//设置超时
rc = nn_setsockopt(pair_socket, 0, NN_SNDTIMEO, &timeo, sizeof(timeo));
rc = nn_setsockopt(pair_socket, 0, NN_RCVTIMEO, &timeo, sizeof(timeo));
//连接服务端
rc = nn_connect(pair_socket, SOCKET_ADDRESS2);
if (rc < 0) {
printf("bind failed! error: %s.\n", nn_err_strerror(errno));
//system("pause");
nn_err_abort();
//return 0;
}
//将hello world复制到buf中
memcpy(buf, HELLOWORLD, str_len);
//发送数据
rc = nn_send(pair_socket, buf, str_len, 0);
if (rc < 0) {
printf("nn_send failed! error: %s.rc = %d.\n", nn_err_strerror(errno), rc);
}
//打印
printf("send:%s\n", buf);
//这里主要是测试使用,平时项目不要使用标签
//接收数据
rc = nn_recv(pair_socket, buf1, 256, 0);
if (rc < 0) {
printf("nn_recv failed! error: %s.rc = %d.\n", nn_err_strerror(errno), rc);
}
//打印
printf("recv:%s\n", buf1);
memset(buf1, 0, 256);
//Sleep(1000);
//关闭套接字
rc = nn_shutdown(pair_socket, 1);
if (rc != 1) {
printf("nn_close failed! error: %s.\n", nn_err_strerror(errno));
//system("pause");
nn_err_abort();
//return 0;
}
std::cout << "testtttttttttttttttttttttttttttttttttt "
<< "hostnameeeeeeeeeeeeeeeeeeeeeeeeeeeeee:" << lease->hostname_ << std::endl;
std::cout << "testtttttttttttttttttttttttttttttttttt "
<< "ipppppppppppppppppppppppppppppppppppp:" << lease->addr_.toText() << std::endl;
std::cout << "lease ALLOC " << __LINE__ << " file name " << __FILE__
<< " HOST:" << lease->hostname_ << std::endl;
std::cout << "lease ALLOC " << __LINE__ << " file name " << __FILE__
<< " IP:" << lease->addr_.toText() << std::endl;
}
It sounds like you need some general information on the KEA software developed by Internet Systems Consortium aka: https://kea.isc.org/ I would read through the Kea docs, mailing lists and the general development wiki to try to hone in on the specific issue you are having with your code. Once you are able explain the issue you are having with your code you can edit your question with your details, and there is a much better chance that you will get more meaningful answers from this site.

How to set extended controls in V4L2 correctly?

I want to record a video from a V4L2 device (from the Raspberry Pi camera) in C.
The recording itself works and I can save the video to a file.
However I need to change the bitrate of the video. From the strace output of the v4l2-ctl --set-ctrl video_bitrate=10000000 command I know that the extended controls API of v4l2 is used to achieve this.
Here's my code which doesn't work so far:
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h> //mmap
#include <fcntl.h>
#include <unistd.h>
#include <linux/videodev2.h>
using namespace std;
#define numbuffers 3
struct picturebuffer
{
void *startadress;
size_t length;
};
//array in which the buffer pointer are being stored
picturebuffer pb[numbuffers];
int main()
{
//open camera
int fd;
fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
cout << "error during opening the camera device!";
cout.flush();
}
cout << "camera opened";
//read capabilities
struct v4l2_capability caps;
if(ioctl(fd, VIDIOC_QUERYCAP, &caps) < 0)
{
cout << "error while reading the capabilities!";
cout.flush();
}
cout << "Capabilities " << caps.capabilities << endl;
//ToDo: check for required capabilities
//set image data
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
format.fmt.pix.width = 1920;
format.fmt.pix.height = 1080;
if(ioctl(fd, VIDIOC_S_FMT, &format) < 0)
{
cout << "error in the image format";
}
cout << "Image properties set" << endl;
//Todo: check if width and height fit together (VIDIOC_ENUM_FRAMESIZES)
//set extended Controls
struct v4l2_ext_controls ecs;
struct v4l2_ext_control ec;
memset(&ecs, 0, sizeof(ecs));
memset(&ec, 0, sizeof(ec));
ec.id = V4L2_CID_MPEG_VIDEO_BITRATE;
ec.value = 10000000;
ec.size = 0;
ecs.controls = &ec;
ecs.count = 1;
ecs.ctrl_class = V4L2_CTRL_CLASS_MPEG;
if(ioctl(fd, VIDIOC_S_EXT_CTRLS, &ecs) < 0)
{
cout << "error in extended controls bitrate";
cout.flush();
}
//allocate buffer in the kernel
struct v4l2_requestbuffers req;
req.count = numbuffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
{
cout << "errro while allocating buffer";
cout.flush();
}
cout << "number of buffers: " << req.count << endl;
cout.flush();
//map buffers into userspace
for(int i=0; i<numbuffers; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
{
cout << "error while querying bufferinfo";
cout.flush();
}
pb[i].startadress = mmap(NULL, bufferinfo.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bufferinfo.m.offset);
pb[i].length = bufferinfo.length;
if(pb[i].startadress == MAP_FAILED)
{
cout << "error during mmap" << endl;
}
memset(pb[i].startadress, 0, bufferinfo.length);
cout << "size of buffer: " << bufferinfo.length << endl;
}
cout << "buffers mapped into userspace" << endl;
cout.flush();
//queue in the buffers
for(int i=0; i<numbuffers; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
{
cout << "error while queueing the buffers in" << endl;
}
}
//since that point the driver starts capturing the pics
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
cout << "error while starting the stream" << endl;
}
int file;
if((file = open("/home/pi/image.h264", O_WRONLY | O_CREAT, 0660)) < 0)
{
cout << "error while writing the file";
}
//loop for managing the pics
for(int i=0; i<100; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0)
{
cout << "error while getting the buffer!" << endl;
}
//do anything with the pic
char buf[pb[bufferinfo.index].length];
memcpy(&buf, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
cout << bufferinfo.index << endl;
cout.flush();
//write picture into the file
write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
{
cout << "error while enqueuing the buffer" << endl;
}
}
close(file);
if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0)
{
cout << "error while stopping the stream" << endl;
}
//clean up
for(int i=0; i<numbuffers; i++)
{
if(munmap(pb[i].startadress, pb[i].length) < 0)
{
cout << "error during unmap";
}
}
//close camera file
close(fd);
cout << "!!!Hello World!!!" << endl;
cout.flush();
return 0;
}
The ioctl call seems to succeed, however my output file always has the same size as of 199,2 MB. Does someone know what´s wrong in the code ?
You need to check if the camera driver supports that IOCTL command. If the driver doesn't support the IOCTL command by not implementing it, you still can execute the command and it is routed to v4l2 default implementation, no actual changes are applied to the camera setting
Try to change the lines:
pb[bufferinfo.index].length
By:
pb[bufferinfo.index].bytesused
For example:
write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].bytesused);

iTunes COM for Windows SDK IITUserPlaylist::AddFile access violation

I am just try to write simple program for some practice. But iTunes COM for Windows SDK threw me a little surprise.
I am want to create playlist and add file to it but when i call IITUserPlaylist::AddFile program crash with access violation. I can all other methods like Delete etc.
Project (MSVC10): http://www76.zippyshare.com/v/34795637/file.html
#include <iostream>
#include <windows.h>
#include <comutil.h>
#include "iTunesCOMInterface.h"
int main(int argc, char* argv[])
{
CoInitialize(0);
HRESULT hRes;
IiTunes* itunes = 0;
// note - CLSID_iTunesApp and IID_IiTunes are defined in iTunesCOMInterface_i.c
hRes = ::CoCreateInstance(CLSID_iTunesApp, NULL, CLSCTX_LOCAL_SERVER, IID_IiTunes, (PVOID *)&itunes);
if(hRes != S_OK && itunes == nullptr)
{
std::cout << "Can not create iTunesApp instance" << std::endl;
CoUninitialize();
return 1;
}
IITLibraryPlaylist* mainLibrary = 0;
hRes = itunes->get_LibraryPlaylist(&mainLibrary);
if(hRes != S_OK || mainLibrary == 0)
{
std::cout << "Can not get main library" << std::endl;
itunes->Release();
CoUninitialize();
return 1;
}
IITSource* mainLibrarySource = 0;
hRes = itunes->get_LibrarySource(&mainLibrarySource);
if(hRes != S_OK || mainLibrarySource == 0)
{
std::cout << "Can not get library source" << std::endl;
mainLibrary->Release();
itunes->Release();
CoUninitialize();
return 1;
}
IITPlaylistCollection* playlistCollection = 0;
hRes = mainLibrarySource->get_Playlists(&playlistCollection);
if(hRes != S_OK || playlistCollection == 0)
{
std::cout << "Can not get source playlists" << std::endl;
mainLibrarySource->Release();
mainLibrary->Release();
itunes->Release();
CoUninitialize();
return 1;
}
BSTR playlistName = SysAllocString(L"SoundFrost playlist");
IITPlaylist* ownPlaylist = 0;
//TODO: But there can be additional playlists with the same name, since playlist names are not unique
hRes = playlistCollection->get_ItemByName(playlistName, &ownPlaylist);
if(hRes != S_OK || ownPlaylist == 0)
{
//just create new
hRes = itunes->CreatePlaylist(playlistName, &ownPlaylist);
if(hRes != S_OK || ownPlaylist == 0)
{
std::cout << "Can not create playlist";
SysFreeString(playlistName);
playlistCollection->Release();
mainLibrarySource->Release();
mainLibrary->Release();
itunes->Release();
CoUninitialize();
return 1;
}
}
SysFreeString(playlistName);
ITPlaylistKind playlistKind;
hRes = ownPlaylist->get_Kind(&playlistKind);
if(hRes == S_OK && playlistKind == ITPlaylistKindUser)
{
IITUserPlaylist* ownUserPlaylist = static_cast<IITUserPlaylist*>(ownPlaylist);
if(ownUserPlaylist != 0)
{
BSTR filePath = SysAllocString(L"C:\\test.mp3");
IITOperationStatus* status;
//hRes = mainLibrary->AddFile(filePath, &status);
//hRes = ownUserPlaylist->AddFile(filePath, &status);
SysFreeString(filePath);
}
}
playlistCollection->Release();
ownPlaylist->Release();
mainLibrarySource->Release();
mainLibrary->Release();
itunes->Release();
CoUninitialize();
return 0;
}
If i call IITLibraryPlaylist::AddFile all was right.
Just uncomment 95 or 96 line for test.
Simple C# code works fine:
iTunesApp itunes = new iTunesLib.iTunesApp();
IITUserPlaylist playlist = itunes.CreatePlaylist("C# playlist") as IITUserPlaylist;
IITOperationStatus status = playlist.AddFile("C:\\test.mp3");
I can not understand why this is happening.
You can't really do this with COM:
IITUserPlaylist* ownUserPlaylist = static_cast<IITUserPlaylist*>(ownPlaylist);
You're just casting an interface pointer into another interface pointer. You must do a QueryInterface instead:
HRESULT hr = ownPlaylist->QueryInterface(IID_IITUserPlaylist, (void**)&ownUserPlaylist);

How to organize queues for each request-handling in new thread?

I need help with organizing each request-handling for incoming connection in new thread (code is at the bottom of this topic).
I don't know at all how to organize manually ( without using boost/threadpool ) queue with handling each request? How should I solve such problem with non-using boost etc?
Cause, I want do it manually, and I don't understand how do the next:
Listening for each new connection
If I've got new connection, then send in new thread the handling
When thread ends handling process, close this thread
I have tried to do such stuff with while(true); but don't know how to organize well the request-queue to handle each HTTP-request.
My code is:
#include <iostream>
#include <Windows.h>
#pragma comment(lib, "Ws2_32.lib")
typedef struct Header
{
friend struct Net;
private:
WORD wsa_version;
WSAData wsa_data;
SOCKET sock;
SOCKADDR_IN service;
char *ip;
unsigned short port;
public:
Header(void)
{
wsa_version = 0x202;
ip = "0x7f.0.0.1";
port = 0x51;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(port);
}
} Header;
typedef struct Net
{
private:
int result;
HANDLE thrd;
DWORD exit_code;
void WSAInit(WSAData *data, WORD *wsa_version)
{
result = WSAStartup(*wsa_version, &(*data));
if(result != NO_ERROR)
{
std::cout << "WSAStartup() failed with the error: " << result << std::endl;
}
else
{
std::cout << (*data).szDescription << " " << (*data).szSystemStatus << std::endl;
}
}
void SocketInit(SOCKET *my_socket)
{
(*my_socket) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if((*my_socket) == INVALID_SOCKET)
{
std::cout << "Socket initialization failed with the error: " << WSAGetLastError() << std::endl;
WSACleanup();
}
else
{
std::cout << "Socket initialization successful!" << std::endl;
}
}
void SocketBind(SOCKET *my_socket, SOCKADDR_IN *service)
{
result = bind((*my_socket), (SOCKADDR*)&(*service), sizeof(*service));
if(result == SOCKET_ERROR)
{
std::cout << "Socket binding failed with the error: " << WSAGetLastError() << std::endl;
closesocket((*my_socket));
WSACleanup();
}
else
{
std::cout << "Socket binding successful!" << std::endl;
}
result = listen(*my_socket, SOMAXCONN);
if(result == SOCKET_ERROR)
{
std::cout << "Socket listening failed with the error: " << WSAGetLastError() << std::endl;
}
else
{
std::cout << "Listening to the socket..." << std::endl;
}
}
void SocketAccept(SOCKET *my_socket)
{
SOCKET sock_accept = accept((*my_socket), 0, 0);
if(sock_accept == INVALID_SOCKET)
{
std::cout << "Accept failed with the error: " << WSAGetLastError() << std::endl;
closesocket(*my_socket);
WSACleanup();
}
else
{
std::cout << "Client socket connected!" << std::endl;
thrd = CreateThread(NULL, 0, &Net::Threading, &sock_accept, 0, NULL);
}
}
static void HandleRequest(char response[], int length)
{
std::cout << std::endl;
for(int i = 0; i < length; i++)
{
std::cout << response[i];
}
std::cout << std::endl;
}
static DWORD WINAPI Threading(LPVOID lpParam)
{
SOCKET *my_socket = (SOCKET*)lpParam;
char data[0x400];
int result = recv((*my_socket), data, sizeof(data), 0);
HandleRequest(data, result);
char *response = "HTTP/1.1 200 OK\r\nServer: Amegas.sys-IS/1.0\r\nContent-type: text/html\r\nSet-Cookie: ASD643DUQE7423HFDG; path=/\r\nCache-control: private\r\n\r\n<h1>Hello World!</h1>\r\n\r\n";
result = send((*my_socket), response, (int)strlen(response), 0);
if(result == SOCKET_ERROR)
{
std::cout << "Sending data via socket failed with the error: " << WSAGetLastError() << std::endl;
closesocket((*my_socket));
WSACleanup();
}
else
{
result = shutdown((*my_socket), 2);
}
return 0;
}
public:
Net(void)
{
Header *obj_h = new Header();
WSAInit(&obj_h->wsa_data, &obj_h->wsa_version);
SocketInit(&obj_h->sock);
SocketBind(&obj_h->sock, &obj_h->service);
SocketAccept(&obj_h->sock);
delete obj_h;
}
} Net;
int main(void)
{
Net *obj_net = new Net();
delete obj_net;
return 0;
}
Your OS will handle the accept() queueing - don't worry too much about it. Simple synchronous servers tend to run like this:
socket listeningSocket:=socket.create;
listeningSocket.bind('0.0.0.0',80); // address/port
listeningSocket.listen;
while(true){
socket serverClientSocket=accept(listeningSocket);
createThread(&serverClientThread,serverClientSocket);
}
void serverClientThread(void *param)
{
inBuffer char[256];
socket myServerClientSocket=(socket)param;
while(true){
int bytesRx=recv(myServerClientSocket,&inBuffer,size(inBuffer));
if (bytesRx>0){
if doSomethingWith(&inBuffer,bytesRx) // not necessarily size(inBuffer) bytes!!
{
send(myServerClientSocket,"Reply from server\r\n");
}
}
else
return; // on error or connection closed
}
}
The one listening thread, (can be main thread in console apps), runs the accept() loop foerver. The separate serverClientThread instances run until their client disconects or some other error occurs.

Resources