How to set extended controls in V4L2 correctly? - c

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);

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;
}
}

ffmpeg rtsp on C

I need to write RTSP steram from IP-cam to file. I use FFMPEG to do this. I found code example on C++, but i need to use only C. Can anyone help me?
i have problems in file operations. how can i write stream to file?
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libswscale/swscale.h>
}
int main(int argc, char** argv) {
// Open the initial context variables that are needed
SwsContext *img_convert_ctx;
AVFormatContext* format_ctx = avformat_alloc_context();
AVCodecContext* codec_ctx = NULL;
int video_stream_index;
// Register everything
av_register_all();
avformat_network_init();
//open RTSP
if (avformat_open_input(&format_ctx, "rtsp://134.169.178.187:8554/h264.3gp",
NULL, NULL) != 0) {
return EXIT_FAILURE;
}
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
return EXIT_FAILURE;
}
//search video stream
for (int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
}
AVPacket packet;
av_init_packet(&packet);
//open output file
AVFormatContext* output_ctx = avformat_alloc_context();
AVStream* stream = NULL;
int cnt = 0;
//start reading packets from stream and write them to file
av_read_play(format_ctx); //play RTSP
// Get the codec
AVCodec *codec = NULL;
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
exit(1);
}
// Add this to allocate the context by codec
codec_ctx = avcodec_alloc_context3(codec);
avcodec_get_context_defaults3(codec_ctx, codec);
avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec);
std::ofstream output_file;
if (avcodec_open2(codec_ctx, codec, NULL) < 0)
exit(1);
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,
codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width,
codec_ctx->height);
uint8_t* picture_buffer = (uint8_t*) (av_malloc(size));
AVFrame* picture = av_frame_alloc();
AVFrame* picture_rgb = av_frame_alloc();
int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width,
codec_ctx->height);
uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2));
avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P,
codec_ctx->width, codec_ctx->height);
avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24,
codec_ctx->width, codec_ctx->height);
while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames
std::cout << "1 Frame: " << cnt << std::endl;
if (packet.stream_index == video_stream_index) { //packet is video
std::cout << "2 Is Video" << std::endl;
if (stream == NULL) { //create stream in file
std::cout << "3 create stream" << std::endl;
stream = avformat_new_stream(output_ctx,
format_ctx->streams[video_stream_index]->codec->codec);
avcodec_copy_context(stream->codec,
format_ctx->streams[video_stream_index]->codec);
stream->sample_aspect_ratio =
format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio;
}
int check = 0;
packet.stream_index = stream->id;
std::cout << "4 decoding" << std::endl;
int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet);
std::cout << "Bytes decoded " << result << " check " << check
<< std::endl;
if (cnt > 100) //cnt < 0)
{
sws_scale(img_convert_ctx, picture->data, picture->linesize, 0,
codec_ctx->height, picture_rgb->data, picture_rgb->linesize);
std::stringstream file_name;
file_name << "test" << cnt << ".ppm";
output_file.open(file_name.str().c_str());
output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height
<< " 255\n";
for (int y = 0; y < codec_ctx->height; y++) {
for (int x = 0; x < codec_ctx->width * 3; x++)
output_file
<< (int) (picture_rgb->data[0]
+ y * picture_rgb->linesize[0])[x] << " ";
}
output_file.close();
}
cnt++;
}
av_free_packet(&packet);
av_init_packet(&packet);
}
av_free(picture);
av_free(picture_rgb);
av_free(picture_buffer);
av_free(picture_buffer_2);
av_read_pause(format_ctx);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
return (EXIT_SUCCESS);
}
please help me to compile this by C-compiler.

multiple threads reading a file: pread or multiple fds

I have a multi-threaded program and I want to have each thread read from the same file and have the same data
I know that from pread(2) it is thread safe; however, I'm concerned about speed and not memory.
Will it be faster to have multiple threads read from the same file descriptor using pread or would it be faster for each individual thread to have its own file descriptor to the same file and read from there?
My thought is, if pread is atomic, then that prevents another thread from reading at the same time; however, if having lots of threads each with their own fd and the OS needs to service each read, then all that context switching might take up more time.
Having the same requirement I did a test for this. According to the test on a SSD and a HDD,
pread - improves the read speed, but if same FD is used for the writing, write becomes slow.
read (with a separate FD) - read operations are slower compared to pread. But it does NOT impact write operations (done using a separate FD).
So best option is to,
Use a separate FD for writing (Write Only mode)
Open a single FD (Read only mode) and use it across multiple threads using pread
results on a SSD (read/write count 10,000,000)
-
pread (same FD used for write and read)
read using a different FD
Read
25 sec +
27 sec +
Write
38 sec +
33 sec+
Code used for the test
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <sstream>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include <memory>
#include <atomic>
#include <thread>
off_t tell(int fd)
{
return lseek(fd, 0, SEEK_CUR);
}
inline int64_t getMicroSecDiff(const timeval& begin, const timeval& end)
{
constexpr uint32_t MicroSecPerSec = 1000 * 1000;
return (end.tv_sec - begin.tv_sec) * MicroSecPerSec + (end.tv_usec - begin.tv_usec);
}
inline int64_t getMicroSecDiffFrom(const timeval& begin)
{
timeval end;
gettimeofday(&end, nullptr);
return getMicroSecDiff(begin, end);
}
using namespace std;
int g_fileFd_A = -1;
int g_fileFd_B = -1;
std::atomic<int64_t> g_lastFileAPos = { -1 };
std::atomic<int64_t> g_lastFileBPos = { -1 };
std::atomic<bool> g_writeCompleted = { false };
const int WriteSz = 1;
uint64_t g_writeCount = 0;
void writer(int fdA, int fdB)
{
timeval begin;
gettimeofday(&begin, nullptr);
for (size_t i = 0; i < g_writeCount; i++)
{
int64_t fileAPosition = tell(fdA);
int64_t fileBPosition = tell(fdB);
auto written = write(fdA, "A", WriteSz);
assert(written == WriteSz);
written = write(fdB, "b", WriteSz);
assert(written == WriteSz);
g_lastFileAPos.store(fileAPosition, std::memory_order_relaxed);
g_lastFileBPos.store(fileBPosition, std::memory_order_relaxed);
}
g_writeCompleted = true;
auto diff = getMicroSecDiffFrom(begin);
std::ostringstream oss;
oss << "Write time: " << diff / 1000000 << " sec " << diff % 1000000 << " us" << endl;
cout << oss.str();
}
void reader(bool duplicateFds)
{
char bufferA[8];
char bufferB[8];
int failedCount = 0;
int fdA, fdB;
if (duplicateFds)
{
fdA = open("./A", O_RDONLY);
fdB = open("./B", O_RDONLY);
}
else
{
fdA = g_fileFd_A;
fdB = g_fileFd_B;
}
timeval begin;
gettimeofday(&begin, nullptr);
size_t iteNo = 0;
//for (; g_writeCompleted.load(memory_order_relaxed) == false; iteNo++)
for (; iteNo < g_writeCount; iteNo++)
{
off_t posA = g_lastFileAPos.load(std::memory_order_relaxed);
off_t posB = g_lastFileBPos.load(std::memory_order_relaxed);
if (posA < 0 or posB < 0)
{
iteNo--;
gettimeofday(&begin, nullptr);
continue;
}
int readSzA;
int readSzB;
off_t readPosA = rand();
off_t readPosB = rand();
if (readPosA > posA)
{
readPosA = posA;
}
if (readPosB > posB)
{
readPosB = posB;
}
if (duplicateFds)
{
lseek(fdA, readPosA, SEEK_SET);
lseek(fdB, readPosB, SEEK_SET);
readSzA = read(fdA, bufferA, WriteSz);
readSzB = read(fdB, bufferB, WriteSz);
}
else
{
readSzA = pread(fdA, bufferA, WriteSz, readPosA);
readSzB = pread(fdB, bufferB, WriteSz, readPosB);
}
if (readSzA < WriteSz or readSzB < WriteSz)
{
failedCount++;
if (failedCount % 1000 == 0)
{
cout << " " << failedCount;
cout.flush();
}
}
}
auto diff = getMicroSecDiffFrom(begin);
std::ostringstream oss;
oss << "Read time: " << diff / 1000000 << " sec " << diff % 1000000 << " us" << " ReadCount=" << iteNo << endl;
oss << "failedCount=" << failedCount << endl;
cout << oss.str();
if (duplicateFds)
{
close(fdA);
close(fdB);
}
}
int main (int argc, char** argv)
{
if (argc < 3)
{
cout << "usage: " << argv[0] << " duplicateFds" << " write-count" << endl;
return 0;
}
bool duplicateFds = atoi(argv[1]);
g_writeCount = atoi(argv[2]);
cout << "duplicateFds=" << duplicateFds << " write-count=" << g_writeCount << endl;
if (duplicateFds)
{
g_fileFd_A = open("./A", O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
g_fileFd_B = open("./B", O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
}
else
{
g_fileFd_A = open("./A", O_RDWR | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
g_fileFd_B = open("./B", O_RDWR | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
}
std::thread readerThread1(reader, duplicateFds);
std::thread readerThread2(reader, duplicateFds);
std::thread writerThread(writer, g_fileFd_A, g_fileFd_B);
readerThread1.join();
readerThread2.join();
writerThread.join();
close(g_fileFd_A);
close(g_fileFd_B);
return 0;
}

avformat_write_header fails with error "invalid argument

I'm trying to write a chunk of a mp4 file to a .ts file, which does not yet exist.
So first I create AVFormatContext this way:
AVOutputFormat *oformat = av_guess_format( NULL,
"mpegts",
"video/x-mpegts" );
AVFormatContext * outFormatContext = NULL;
avformat_alloc_output_context2( &outFormatContext, oformat, NULL, dst_file)
outFormatContext is created and outFormatContext->oformat is set to oformat. Then I open I/O context on outFormatContext:
avio_open(&outFormatContext->pb, dst_file, AVIO_FLAG_WRITE)
avformat_write_header( outFormatContext, NULL );
according to this this is enough for avformat_write_header to work but it fails with error "invalid argument".
What else needs to be done to successfully write the header?
Although it's a little bit late, I hope it would be helpful.
Here is my way to call avformat_write_header, you should have a stream provided to write the header.
AVFormatContext* pOutFormatContext;
AVOutputFormat* avOutputFormat;
if ((avOutputFormat = av_guess_format(NULL, "mp4", "video/mp4")) == NULL) {
cerr << "Could not guess output format" << endl;
return -1;
}
avformat_alloc_output_context2(&pOutFormatContext,
av_guess_format("mp4", NULL, "video/mp4"), NULL, NULL);
if (pOutFormatContext == NULL) {
cerr << "Could not allocate output context" << endl;
return -1;
}
for (int i = 0; i < avFormatContext->nb_streams; i++) {
AVStream* inAVStream = avFormatContext->streams[i];
AVStream* outAVStream = avformat_new_stream(pOutFormatContext, inAVStream->codec->codec);
if (avcodec_copy_context(outAVStream->codec, inAVStream->codec) < 0) {
cerr << "Failed to copy codec context" << endl;
return -1;
}
outAVStream->codec->codec_tag = 0;
if (pOutFormatContext->oformat->flags & AVFMT_GLOBALHEADER) {
outAVStream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
avio_open(&pOutFormatContext->pb, "test.mp4", AVIO_FLAG_READ_WRITE);
if (pOutFormatContext->pb == NULL) {
cerr << "Could not open for writing" << endl;
return -1;
}
if (avformat_write_header(pOutFormatContext, NULL) != 0) {
cerr << "Could not write header" << endl;
return -1;
}

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