I'm trying to download picture from website. The problem is that even tho I get all the content from HTTP response body, file won't open. I've been trying to solve this but I can't find the real problem. One thing I did notice is that picture downloaded using chromium displays different characters than picture downloaded from my code using command:
$ cat picture.png | less
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
using std::cout;
using std::endl;
//with this function I remove HTTP header info, so I only get content.
char *removeHTTPHeader(char *buffer) {
char *t = strstr(buffer, "\r\n\r\n");
t = t + 4;
return t;
}
void getPicture(const int &socketfd, const int &bSize) {
std::ofstream file("picture.png",
std::ofstream::binary | std::ofstream::out);
char buffer[bSize];
ssize_t bReceived;
bReceived = recv(socketfd, buffer, bSize, 0);
char *t = removeHTTPHeader(buffer);
file.write(t, strlen(t));
memset(buffer, 0, bSize);
while ((bReceived = recv(socketfd, buffer, bSize, 0)) > 0) {
file.write(buffer, bReceived);
memset(buffer, 0, bSize);
}
file.close();
}
int main() {
int status;
addrinfo host_info;
addrinfo *host_info_list;
memset(&host_info, 0, sizeof(host_info));
host_info.ai_family = AF_UNSPEC;
host_info.ai_socktype = SOCK_STREAM;
host_info.ai_protocol = 0;
status = getaddrinfo("www.pngimg.com", "80", &host_info, &host_info_list);
if (status != 0) {
cout << "getaddrinfo error" << endl;
}
int socketfd;
socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype,
host_info_list->ai_protocol);
addrinfo *rp;
for (rp = host_info_list; rp != NULL; rp = rp->ai_next) {
socketfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (socketfd == -1) {
cout << "socket error" << endl;
}
if (connect(socketfd, rp->ai_addr, rp->ai_addrlen) != -1) {
break;
}
close(socketfd);
}
if (rp == NULL) {
cout << "Could not connect!" << endl;
exit(EXIT_FAILURE);
}
freeaddrinfo(host_info_list);
const char *msg =
"GET /upload/water_PNG3290.png HTTP/1.1\r\nhost: www.pngimg.com\r\nConnection: close\r\n\r\n";
status = send(socketfd, msg, strlen(msg), 0);
if (status == -1) {
cout << "error sending" << endl;
exit(EXIT_FAILURE);
}
getPicture(socketfd, 1024);
close(socketfd);
return 0;
}
Here is picture from using cat command:
terminal above is picture from my code, below is picture from chromium "save as"
Problem was that I didn't know that in C style string you can't do strlen on binary data. That's why I had to add counter in function removeHTTPHeader. Below are function getPicture and removeHTTPHeader that I've changed.
char *removeHTTPHeader(char *buffer, int &bodySize) {
char *t = strstr(buffer, "\r\n\r\n");
t = t + 4;
for (auto it = buffer; it != t; ++it) {
++bodySize;
}
return t;
}
void getPicture(const int &socketfd, const int &bSize) {
std::ofstream file("picture.png",
std::ofstream::binary | std::ofstream::out);
char buffer[bSize];
ssize_t bReceived;
bReceived = recv(socketfd, buffer, bSize, 0);
int bodySize = 0;
char *t = removeHTTPHeader(buffer, bodySize);
bodySize = bReceived - bodySize;
file.write(t, bodySize);
memset(buffer, 0, bSize);
while ((bReceived = recv(socketfd, buffer, bSize, 0)) > 0) {
file.write(buffer, bReceived);
memset(buffer, 0, bSize);
}
file.close();
}
Related
I'm trying to encode a video (mov) from png images with alpha channel in FFMPEG.
Using cmd:
ffmpeg -i %d.png -r 25 -vcodec png -b:v 2500K out.mov -y
It works well.
I need to create video from png images with alpha channel in c code
Now I want to use in c++ code,
#include "VideoCapture.h"
#define FINAL_FILE_NAME "record.mov"
#define VIDEO_TMP_FILE "tmp.avi"
using namespace std;
FILE *fp_write;
static int write_packet(void *opaque, uint8_t *buf, size_t buf_size)
{
struct buffer_data *bd = (struct buffer_data *)opaque;
printf("ptr :%p size:%zu\n", bd->ptr, bd->size);
memcpy(bd->ptr + bd->size, buf, buf_size);
bd->size = buf_size + bd->size;
return 1;
}
void VideoCapture::Init(string filename, int width, int height, int fpsrate, int bitrate) {
fps = fpsrate;
int err;
uint8_t *outbuffer=nullptr;
outbuffer=(uint8_t*)av_malloc(32768);
bd = (struct buffer_data*)malloc(sizeof(struct buffer_data));
bd->ptr = (uint8_t*)av_malloc(1000000000);
bd->size = 0;
avio_out =avio_alloc_context(outbuffer, 32768,1,bd,nullptr,write_packet,nullptr);
if (!(oformat = av_guess_format("mov", nullptr, nullptr))) {
cout << "Failed to define output format"<< endl;
return;
}
oformat->video_codec = AV_CODEC_ID_PNG;
cout << "oformat->video_codec " << oformat->video_codec << endl;
if ((err = avformat_alloc_output_context2(&ofctx, oformat, nullptr, nullptr) < 0)) {
cout <<"Failed to allocate output context"<< endl;
//Free();
return;
}
cout << "oformat->video_codec " << oformat->video_codec << endl;
if (!(codec = avcodec_find_encoder(oformat->video_codec))) {
cout <<"Failed to find encoder"<< endl;
//Free();
return;
}
if (!(videoStream = avformat_new_stream(ofctx, codec))) {
cout <<"Failed to create new stream"<< endl;
//Free();
return;
}
if (!(cctx = avcodec_alloc_context3(codec))) {
cout <<"Failed to allocate codec context"<< endl;
//Free();
return;
}
videoStream->codecpar->codec_id = oformat->video_codec;
videoStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
videoStream->codecpar->width = width;
videoStream->codecpar->height = height;
videoStream->codecpar->format = AV_PIX_FMT_RGBA;
videoStream->codecpar->bit_rate = bitrate * 1000;
videoStream->time_base = { 1, fps };
avcodec_parameters_to_context(cctx, videoStream->codecpar);
cctx->time_base = { 1, fps };
cctx->max_b_frames = 2;
cctx->gop_size = 12;
if (videoStream->codecpar->codec_id == AV_CODEC_ID_PNG) {
//av_opt_set(cctx, "preset", "ultrafast", 0);
}
if (ofctx->oformat->flags & AVFMT_GLOBALHEADER) {
cctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
avcodec_parameters_from_context(videoStream->codecpar, cctx);
if ((err = avcodec_open2(cctx, codec, nullptr)) < 0) {
cout <<"Failed to open codec"<< endl;
Free();
return;
}
ofctx->pb = avio_out;
//不知道有什么用
ofctx->flags=AVFMT_FLAG_CUSTOM_IO;
if ((err = avformat_write_header(ofctx, nullptr)) < 0) {
cout <<"Failed to write header"<< endl;
Free();
return;
}
//av_dump_format(ofctx, 0, VIDEO_TMP_FILE, 1);
cout << "init com" << endl;
}
void VideoCapture::AddFrame(uint8_t *data) {
int err;
if (!videoFrame) {
videoFrame = av_frame_alloc();
videoFrame->format = AV_PIX_FMT_RGBA;
videoFrame->width = cctx->width;
videoFrame->height = cctx->height;
if ((err = av_frame_get_buffer(videoFrame, 32)) < 0) {
cout <<"Failed to allocate picture"<< endl;
return;
}
}
cout << "finish" << endl;
if (!swsCtx) {
swsCtx = sws_getContext(cctx->width, cctx->height, AV_PIX_FMT_RGBA, cctx->width, cctx->height, AV_PIX_FMT_RGBA, SWS_BICUBIC, 0, 0, 0);
}
int inLinesize[1] = { 4 * cctx->width};
sws_scale(swsCtx, (const uint8_t * const *)&data, inLinesize, 0, cctx->height, videoFrame->data, videoFrame->linesize);
videoFrame->pts = (1.0 / 30.0) * 90000 * (frameCounter++);;
if ((err = avcodec_send_frame(cctx, videoFrame)) < 0) {
cout <<"Failed to send frame"<< endl;
return;
}
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
if (avcodec_receive_packet(cctx, &pkt) == 0) {
pkt.flags |= AV_PKT_FLAG_KEY;
av_interleaved_write_frame(ofctx, &pkt);
av_packet_unref(&pkt);
}
}
void VideoCapture::Finish() {
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
for (;;) {
avcodec_send_frame(cctx, nullptr);
if (avcodec_receive_packet(cctx, &pkt) == 0) {
av_interleaved_write_frame(ofctx, &pkt);
av_packet_unref(&pkt);
}
else {
break;
}
}
av_write_trailer(ofctx);
/*
if (!(oformat->flags & AVFMT_NOFILE)) {
int err = avio_close(ofctx->pb);
if (err < 0) {
cout <<"Failed to close file"<< endl;
}
}
*/
fp_write = fopen(VIDEO_TMP_FILE, "wb");
if (!feof(fp_write)) {
int true_size = fwrite(bd->ptr, 1, bd->size, fp_write);
std::cout << true_size << std::endl;
}
fcloseall();
//Remux();
//Free();
}
void VideoCapture::Free() {
if (videoFrame) {
//std::cout << "videoFrame " << std::endl;
av_frame_free(&videoFrame);
}
if (cctx) {
//std::cout << "cctx" << std::endl;
avcodec_free_context(&cctx);
}
if (ofctx) {
//std::cout << "ofctx" << ofctx << std::endl;
avformat_free_context(ofctx);
}
if (swsCtx) {
//std::cout << "swsCtx" << std::endl;
sws_freeContext(swsCtx);
}
/*
if (bd->ptr != (void*)0)
{
free(bd->ptr);
}
free(bd);*/
}
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
struct buffer_data *bd = (struct buffer_data *)opaque;
buf_size = FFMIN(buf_size, bd->size);
if(buf_size == 0) return -1;
//printf("read ptr:%p size:%zu\n", bd->ptr, bd->size);
/* copy internal buffer data to buf */
memcpy(buf, bd->ptr, buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;
return buf_size;
}
void VideoCapture::Remux() {
AVFormatContext *ifmt_ctx = nullptr, *ofmt_ctx = nullptr;
int err;
unsigned char* inbuffer=nullptr;
inbuffer=(unsigned char*)av_malloc(32768);
ifmt_ctx = avformat_alloc_context();
AVIOContext *avio_in =avio_alloc_context(inbuffer, 32768 ,0,bd,read_packet,nullptr,nullptr);
ifmt_ctx->pb=avio_in;
if (!(oformat = av_guess_format(nullptr, nullptr, "h264"))) {
cout << "Failed to define output format";
return;
}
if ((err = avformat_open_input(&ifmt_ctx, "nullptr", 0, 0)) < 0) {
cout <<"Failed to open input file for remuxing"<< endl;
}
if ((err = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
cout <<"Failed to retrieve input stream information"<< endl;
}
if ((err = avformat_alloc_output_context2(&ofmt_ctx, oformat, nullptr, nullptr))) {
cout <<"Failed to allocate output context"<< endl;
}
AVStream *inVideoStream = ifmt_ctx->streams[0];
AVStream *outVideoStream = avformat_new_stream(ofmt_ctx, nullptr);
if (!outVideoStream) {
cout <<"Failed to allocate output video stream" << endl;
}
outVideoStream->time_base = { 1, fps };
avcodec_parameters_copy(outVideoStream->codecpar, inVideoStream->codecpar);
outVideoStream->codecpar->codec_tag = 0;
uint8_t *outbuffer=nullptr;
outbuffer=(uint8_t*)av_malloc(32768);
res_video = (struct buffer_data*)malloc(sizeof(struct buffer_data));
res_video->ptr = (uint8_t*)av_malloc(100000000);
res_video->size = 0;
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_out =avio_alloc_context(outbuffer, 32768,1, res_video, nullptr, write_packet, nullptr);
ofmt_ctx->pb = avio_out;
}
AVDictionary* opts = nullptr;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
if ((err = avformat_write_header(ofmt_ctx, &opts)) < 0) {
cout <<"Failed to write header to output file"<< endl;
}
AVPacket videoPkt;
int ts = 0;
while (true) {
if ((err = av_read_frame(ifmt_ctx, &videoPkt)) < 0) {
break;
}
videoPkt.stream_index = outVideoStream->index;
videoPkt.pts = ts;
videoPkt.dts = ts;
videoPkt.duration = av_rescale_q(videoPkt.duration, inVideoStream->time_base, outVideoStream->time_base);
ts += videoPkt.duration;
videoPkt.pos = -1;
if ((err = av_interleaved_write_frame(ofmt_ctx, &videoPkt)) < 0) {
cout <<"Failed to mux packet"<< endl;
av_packet_unref(&videoPkt);
break;
}
av_packet_unref(&videoPkt);
}
av_write_trailer(ofmt_ctx);
cout << "res_video->size " << res_video->size << endl;
fp_write=fopen(FINAL_FILE_NAME,"wb");
if(!feof(fp_write)){
int true_size=fwrite(res_video->ptr,1, res_video->size,fp_write);
std::cout << true_size << std::endl;
}
fcloseall();
}
Header file:
#ifndef _RENDER_H_
#define _RENDER_H_
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <cstring>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <string>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavcodec/avfft.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfilter.h>
//#include <libavfilter/avfiltergraph.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/opt.h>
#include <libavutil/common.h>
#include <libavutil/channel_layout.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavutil/time.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libavutil/file.h>
//#include "libavcodec/vdpau.h"
#include "libavutil/hwcontext.h"
//#include "libavutil/hwcontext_vdpau.h"
#include <libswscale/swscale.h>
class VideoCapture {
public:
VideoCapture() {
oformat = nullptr;
ofctx = nullptr;
videoStream = nullptr;
videoFrame = nullptr;
swsCtx = nullptr;
frameCounter = 0;
av_register_all();
//av_log_set_callback(avlog_cb);
}
~VideoCapture() {
//Free();
}
void Init(std::string name, int width, int height, int fpsrate, int bitrate);
void AddFrame(uint8_t *data);
void Finish();
private:
AVOutputFormat *oformat;
AVFormatContext *ofctx;
AVIOContext *avio_out;
AVStream *videoStream;
AVFrame *videoFrame;
AVCodec *codec;
AVCodecContext *cctx;
struct buffer_data *bd;
struct buffer_data* res_video;
SwsContext *swsCtx;
//FILE *fp_write;
char* filename;
//int buf_len;
int frameCounter;
int fps;
void Free();
void Remux();
};
struct buffer_data {
uint8_t *ptr;
size_t size; ///< size left in the buffer
};
}
#endif
It got error:
[mov # 0x29bf0c0] muxer does not support non seekable output
Failed to write header
How can I solve this? muxer mov maybe support png encoder
ffmpeg show muxer mov
Default video codec: h264
How can I change the cmd to c++ code?
I am writing a network program in C ++. How it works:
The server streams video for the client in real time.
The client receives the video data.
I tried to set up sending and receiving messages (right during streaming). For this, I started the video in a separate thread.
Messages from the client to the server reach the server without any problems. But if you send messages from the server to the client, then firstly the video itself changes, and some kind of garbage is displayed.
How it works (no)
I understand that this is due to the fact that the client is constantly receiving messages (vide). But is it possible to somehow solve this problem?
Server code
#include "server.h"
int Server::open()
{
WORD DLLVersion = MAKEWORD(2, 1);
if (WSAStartup(DLLVersion, &wsaData) != 0)
{
std::cout << "Error" << std::endl;
exit(1);
}
int sizeofaddr = sizeof(addr);
addr.sin_addr.s_addr = inet_addr(addrss);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
server = socket(AF_INET, SOCK_STREAM, NULL);
bind(server, (SOCKADDR*)&addr, sizeof(addr));
listen(server, SOMAXCONN);
std::cout << "Listening..." << std::endl;
client = accept(server, (SOCKADDR*)&addr, &sizeofaddr);
if (client == 0) {
std::cout << "Error #2\n";
}
else {
std::cout << "Client Connected!\n";
}
}
int Server::sendData(const char *buffer, int len)
{
return send(client, buffer, len, NULL);
}
int Server::recvData(char *buffer, int len)
{
return recv(client, buffer, len, NULL);
}
int Server::close()
{
closesocket(server);
std::cout << "Server is closed" << std::endl;
return 0;
}
Server main
#include "server.h"
#include "opencv2/core/core.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2\video\background_segm.hpp"
#include <opencv2\video\tracking.hpp>
#include <Windows.h>
#include <thread>
#include <string>
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 480
#define CLIENT_CLOSE_CONNECTION_SYMBOl '#'
cv::Mat cameraFeed;
int height, width, IM_HEIGHT, IM_WIDTH, imgSize;
bool is_client_connection_close(const char *msg)
{
for (int i = 0; i < strlen(msg); ++i)
{
if (msg[i] == CLIENT_CLOSE_CONNECTION_SYMBOl)
{
return true;
}
}
return false;
}
void VideoSender(Server server)
{
cv::VideoCapture cap(0);
while (true)
{
cv::Mat frame, image;
if (!cap.read(cameraFeed))
{
std::cout << "Video dont work" << std::endl;
break;
}
height = cameraFeed.rows;
width = cameraFeed.cols;
IM_HEIGHT = FRAME_HEIGHT;
IM_WIDTH = FRAME_WIDTH;
resize(cameraFeed, cameraFeed, cv::Size(IM_WIDTH, IM_HEIGHT));
imgSize = cameraFeed.total()*cameraFeed.elemSize();
server.sendData(reinterpret_cast<char*>(cameraFeed.data), imgSize);
imshow("Video_sending", cameraFeed);
char button = cv::waitKey(10);
if (button == 'q')
{
std::cout << "Stop sending video data..." << std::endl;
cap.release();
cv::destroyWindow("Video_sending");
server.close();
break;
}
}
}
int main(int argc, char* argv[])
{
Server server;
server.open();
std::thread th_video(VideoSender, server);
while (true)
{
//sending message
std::string msg1;
std::getline(std::cin, msg1);
int msg_size1 = msg1.size();
server.sendData((char*)&msg_size1, sizeof(int));
server.sendData(msg1.c_str(), msg_size1);
//receive_message
int msg_size;
server.recvData((char*)&msg_size, sizeof(int));
char *msg = new char[msg_size + 1];
msg[msg_size] = '\0';
server.recvData(msg, msg_size);
std::cout << "Message from client: " << msg
<< " (size: " << msg_size << ")"
<< std::endl;
delete[] msg;
}
system("pause");
return 0;
}
Client code
#include "client.h"
int Client::open()
{
WORD DLLVersion = MAKEWORD(2, 1);
if (WSAStartup(DLLVersion, &wsaData) != 0) {
std::cout << "Error" << std::endl;
exit(1);
}
int sizeofaddr = sizeof(addr);
addr.sin_addr.s_addr = inet_addr(addrs);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
server = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(server, (SOCKADDR*)&addr, sizeof(addr)) != 0) {
std::cout << "Error: failed connect to server.\n";
return 1;
}
std::cout << "Connected!\n";
}
int Client::sendData(const char * buffer, int len)
{
return send(server, buffer, len, NULL);
}
int Client::recvData(char *buffer, int len)
{
return recv(server, buffer, len, NULL);
}
int Client::close()
{
closesocket(server);
std::cout << "Server is closed" << std::endl;
return 0;
}
Client main
#include "client.h"
#include "opencv2/core/core.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2\video\background_segm.hpp"
#include <opencv2\video\tracking.hpp>
#include <Windows.h>
#include <string>
#include <thread>
#pragma warning(disable: 4996)
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 480
int imgSize;
int bytes = 0;
bool running = true;
int msg_size;
void VideoReceiver(Client client)
{
while (running)
{
int IM_HEIGHT = FRAME_HEIGHT;
int IM_WIDTH = FRAME_WIDTH;
cv::Mat img = cv::Mat::zeros(FRAME_HEIGHT, FRAME_WIDTH, CV_8UC3);
imgSize = img.total()*img.elemSize();
const int ah = 921600;
char sockData[ah];
for (int i = 0; i < imgSize; i += bytes)
if ((bytes = client.recvData(sockData + i, imgSize - i)) == 0)
std::cout << "WTF" << std::endl;
int ptr = 0;
for (int i = 0; i < img.rows; ++i)
for (int j = 0; j < img.cols; ++j)
{
img.at<cv::Vec3b>(i, j) = cv::Vec3b(sockData[ptr + 0], sockData[ptr + 1], sockData[ptr + 2]);
ptr = ptr + 3;
}
cv::namedWindow("Reveived_video", cv::WINDOW_AUTOSIZE);
imshow("Reveived_video", img);
char button = cv::waitKey(10);
if (button == 'q')
{
std::cout << "Stop reveiving video data..." << std::endl;
cv::destroyWindow("Reveived_video");
client.close();
break;
}
}
}
void message_sendind(Client client)
{
while (true)
{
//receiv message
int msg_size;
client.recvData((char*)&msg_size, sizeof(int));
char *msg = new char[msg_size + 1];
msg[msg_size] = '\0';
client.recvData(msg, msg_size);
std::cout << "Message from server: " << msg
<< " (size: " << msg_size << ")"
<< std::endl;
delete[] msg;
//sending message
//std::string msg1;
//std::getline(std::cin, msg1);
//int msg_size1 = msg1.size();
//client.sendData((char*)&msg_size1, sizeof(int));
//client.sendData(msg1.c_str(), msg_size1);
}
}
int main(int argc, char* argv[])
{
Client client;
client.open();
std::thread th_video(VideoReceiver, client);
while (true)
{
//receiv message
int msg_size;
client.recvData((char*)&msg_size, sizeof(int));
char *msg = new char[msg_size + 1];
msg[msg_size] = '\0';
client.recvData(msg, msg_size);
std::cout << "Message from server: " << msg
<< " (size: " << msg_size << ")"
<< std::endl;
delete[] msg;
//sending message
std::string msg1;
std::getline(std::cin, msg1);
int msg_size1 = msg1.size();
client.sendData((char*)&msg_size1, sizeof(int));
client.sendData(msg1.c_str(), msg_size1);
}
system("pause");
return 0;
}
I'm trying to create an app which would accept many connections from clients at the same time and it works for me, but it also should download those files at the same time. In this version of server, even if clients are connected simultaneously, files are written one by one.
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
int const max_clients = 100;
int client_socket[max_clients];
for (int i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int opt = TRUE;
if( setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(bind(server_socket,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(listen(server_socket, 5) == SOCKET_ERROR)
{
std::cout << "Nasluchiwanie portu nieudane." << std::endl;
}
else
{
std::cout << "Nasluchiwanie portu " << port << " udane." << std::endl << std::endl;
}
int const buffer_size = 512;
char buffer[buffer_size];
int max_socket_descriptor, socket_descriptor;
int downloaded_files = 1;
fd_set readfds;
while(true)
{
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
max_socket_descriptor = server_socket;
for (int i = 0 ; i < max_clients ; i++)
{
socket_descriptor = client_socket[i];
if(socket_descriptor > 0)
{
FD_SET( socket_descriptor, &readfds);
}
if(socket_descriptor > max_socket_descriptor)
{
max_socket_descriptor = socket_descriptor;
}
}
if ((select( max_socket_descriptor + 1, &readfds, NULL, NULL, NULL) < 0) && (errno != EINTR))
{
std::cout << "Blad funkcji select." << std::endl;
}
if (FD_ISSET(server_socket, &readfds))
{
int new_sockfd;
if ((new_sockfd = accept(server_socket,(SOCKADDR *)&server, &server_sizeof)) == SOCKET_ERROR)
{
std::cout << "Otrzymanie deskryptora nieudane." << std::endl;
}
else
{
for (int i = 0; i < max_clients; i++)
{
if( client_socket[i] == 0 )
{
client_socket[i] = new_sockfd;
std::cout << "Dodawanie do listy socketow jako numer " << i << std::endl;
break;
}
}
}
}
for (int i = 0; i < max_clients; i++)
{
socket_descriptor = client_socket[i];
if (FD_ISSET( socket_descriptor, &readfds))
{
struct sockaddr_in client_address;
char filename[buffer_size];
std::stringstream ip_filename;
ip_filename << "plik" << downloaded_files << "_" << inet_ntoa(client_address.sin_addr);
strcpy(filename, ip_filename.str().c_str());
std::cout << "Nazwa pliku (IP klienta): " << filename << std::endl;
FILE* file;
file = fopen(filename, "wb");
const clock_t begin_time = clock();
int received_size;
do
{
memset(buffer, 0, buffer_size);
received_size = recv(socket_descriptor, buffer, buffer_size, 0);
if (received_size == 0 || received_size == -1)
{
break;
}
fwrite(buffer, sizeof(char), received_size, file);
}
while (received_size != 0);
fclose(file);
std::cout << "Czas wysylania pliku: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << " sekund." << std::endl << std::endl;
closesocket(socket_descriptor);
client_socket[i] = 0;
downloaded_files++;
}
}
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
What should I do to make them write many at the same time? I've tried many modifications of the code above but every time I can't get wanted result.
For example:
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
int const max_clients = 100;
int client_socket[max_clients];
for (int i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int opt = TRUE;
if( setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(bind(server_socket,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(listen(server_socket, 5) == SOCKET_ERROR)
{
std::cout << "Nasluchiwanie portu nieudane." << std::endl;
}
else
{
std::cout << "Nasluchiwanie portu " << port << " udane." << std::endl << std::endl;
}
int const buffer_size = 512;
char buffer[buffer_size];
int max_socket_descriptor;
int downloaded_files = 1;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
max_socket_descriptor = server_socket;
while(true)
{
if ((select( max_socket_descriptor + 1, &readfds, NULL, NULL, NULL) < 0) && (errno != EINTR))
{
std::cout << "Blad funkcji select." << std::endl;
}
for (int i = 0 ; i < max_clients ; i++)
{
if(FD_ISSET(server_socket, &readfds))
{
int new_sockfd;
if ((new_sockfd = accept(server_socket,(SOCKADDR *)&server, &server_sizeof)) == SOCKET_ERROR)
{
std::cout << "Otrzymanie deskryptora nieudane." << std::endl;
}
else
{
for (int i = 0; i < max_clients; i++)
{
if( client_socket[i] == 0 )
{
client_socket[i] = new_sockfd;
FD_SET( client_socket[i], &readfds);
if(client_socket[i] > max_socket_descriptor)
{
max_socket_descriptor = client_socket[i];
}
std::cout << "Dodawanie do listy socketow jako numer " << i << std::endl;
break;
}
}
}
}
if(FD_ISSET(client_socket[i], &readfds))
{
struct sockaddr_in client_address;
char filename[buffer_size];
std::stringstream ip_filename;
ip_filename << "plik" << downloaded_files << "_" << inet_ntoa(client_address.sin_addr);
strcpy(filename, ip_filename.str().c_str());
std::cout << "Nazwa pliku (IP klienta): " << filename << std::endl;
FILE* file;
memset(buffer, 0, buffer_size);
int received_size;
received_size = recv(client_socket[i], buffer, buffer_size, 0);
if (received_size <= 0)
{
closesocket(client_socket[i]);
FD_CLR(client_socket[i], &readfds);
client_socket[i] = 0;
break;
}
else
{
file = fopen(filename, "ab");
fwrite(buffer, sizeof(char), received_size, file);
fclose(file);
}
downloaded_files++;
}
}
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
I thought about opening and closing those files every received packet and appending every packet to them, but I really don't have idea how to do it. The example of modified code was meant to do it, but it doesn't work.
I'm forbidden to use other processes and threads than the main one, so I'm kinda helpless now. Thanks for your help.
You have the basic loop with select in place, which is good.
accept is already (mostly) non-blocking. You just need to turn on non-blocking mode on the client sockets and then you'll be able to handle multiple client reads, writes and accepts in your main select loop.
You can have a vector of client-specific data per client, with each entry containing the client socket, the opened file and any other client-specific state.
After the accept, you create a new client entry and add it to the vector. Then in the main loop you do FD_SET for accept and all client's reads and writes. After the select, you inspect the the FD sets and handle them one by one. For best performance you will want your file I/O also in non-blocking mode, but for this assignment that's probably overkill.
I'm trying to implement transmission of files through UDP protocol in C++.
What I've got is the server which can send a file requested by a client, but it only works for .txt files. When I try to do the same with image or executable, the transmission corrupts and the file is about 0 KB.
Server:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char* notFound = "File not found.";
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int sendFile(FILE* file, char* buffer, int s)
{
int i, len;
if (file == NULL)
{
strcpy(buffer, notFound);
len = strlen(notFound);
buffer[len] = EOF;
return 1;
}
char ch, ch2;
for (i = 0; i < s; i++)
{
ch = fgetc(file);
ch2 = Cipher(ch);
buffer[i] = ch2;
if (ch == EOF)
return 1;
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketServer;
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketServer == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
if(bind(socketServer, (SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
std::cout << "Waiting." << std::endl;
SOCKADDR_IN client;
int len_client = sizeof(client);
FILE* file;
if(recvfrom(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, &len_client) == SOCKET_ERROR) //Odbiór danych od clienta wraz z kontrolą błędów.
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
else
{
file = fopen(buffer, "rb");
std::cout << "Filename: " << buffer << std::endl;
if(file == NULL)
{
std::cout << "Couldnt open a file." << std::endl;
}
else
{
while (true)
{
if(sendFile(file, buffer, bufferSize))
{
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
break;
}
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
clearBuf(buffer);
}
fclose(file);
}
}
closesocket(socketServer);
WSACleanup();
system("pause");
return 0;
}
Client:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int recvFile(char* buffer, int s, FILE* file)
{
int i;
char ch;
for (i = 0; i < s; i++)
{
ch = buffer[i];
ch = Cipher(ch);
if (ch == EOF)
{
return 1;
}
else
{
fprintf(file, "%c", ch);
}
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketClient;
socketClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketClient == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
int serverSizeOf = sizeof(server);
std::cout << "Name of file to send: ";
std::cin >> buffer;
if(sendto(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
FILE* file;
file = fopen(buffer, "ab");
while (true)
{
clearBuf(buffer);
if(recvfrom(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, &serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
if (recvFile(buffer, bufferSize, file))
{
break;
}
fclose(file);
}
closesocket(socketClient);
WSACleanup();
system("pause");
return 0;
}
To do what I said above, I used the tutorial: C program for file Transfer using UDP (Linux).
How can I adapt the code to send other files than .txt only? Thank you in advance.
As said in the comments above you need a data type where EOF has a different value from all other character values, char is inadequate in this respect, especially when you are dealing with binary data.
The following change should improve things
int sendFile(FILE* file, char* buffer, int s)
{
...
for (i = 0; i < s; i++)
{
int ch = fgetc(file);
if (ch == EOF)
return 1;
buffer[i] = Cipher(ch);
}
...
I've decided to change nearly everything in the original solution I tried to implement. The most important changes are reading file using fread and writing it using fwrite.
The file is send in parts of 512 bytes (or less) and those parts are counted in the variable.
If the file requested by a client doesn't exist on the server, special information is sent and the file created to save data is deleted.
Now the program works as expected even for executables and SHA256 of both files, original and received, are the same.
Server:
//SERVER
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
if(bind(server_socket,(SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
std::cout << "Waiting for data." << std::endl;
SOCKADDR_IN client;
int client_sizeof = sizeof(client);
int const buffer_size = 512;
char buffer[buffer_size];
if(recvfrom(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, &client_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
else
{
FILE* file;
file = fopen(buffer, "rb");
std::cout << "Filename: " << buffer << std::endl;
if(file == NULL)
{
std::cout << "Couldn't open the file." << std::endl;
strcpy(buffer, "NOFILE");
if(sendto(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
}
fseek(file, 0, SEEK_END);
int file_size = ftell(file);
size_t reading_size;
int part = 0;
const clock_t begin_time = clock();
while((part * buffer_size) < file_size)
{
fseek(file, (part * buffer_size), SEEK_SET);
reading_size = fread(buffer, 1, buffer_size, file);
if(sendto(server_socket, buffer, reading_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
part++;
}
std::cout << "Sent " << part << " parts of " << buffer_size << " bytes." << std::endl;
std::cout << "Time of sending file: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << " seconds." << std::endl;
strcpy(buffer, "QUIT");
if(sendto(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
fclose(file);
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
Client:
//CLIENT
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET client_socket;
client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(client_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int const buffer_size = 512;
char buffer[buffer_size];
std::cout << "Name of the requested file: ";
std::cin >> buffer;
char filename[buffer_size];
strcpy(filename, buffer);
if(sendto(client_socket, buffer, buffer_size, 0,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(client_socket);
WSACleanup();
exit(1);
}
FILE* file;
file = fopen(filename, "wb");
int received_size = 0;
while(true)
{
received_size = recvfrom(client_socket, buffer, buffer_size, 0,(SOCKADDR *)&server, &server_sizeof);
if(received_size == SOCKET_ERROR)
{
fclose(file);
closesocket(client_socket);
WSACleanup();
exit(1);
}
if(strcmp(buffer, "NOFILE") == 0)
{
std::cout << "The file does not exist on the server." << std::endl;
fclose(file);
remove(filename);
break;
}
else if(strcmp(buffer, "QUIT") == 0)
{
std::cout << "Transmission ended by the server." << std::endl;
break;
}
fwrite(buffer, sizeof(char), received_size, file);
}
fclose(file);
closesocket(client_socket);
WSACleanup();
system("pause");
return 0;
}
I am trying to send a BIGNUM (from openssl/bn.h) over socket, but its behaviour is strange.
I use BN_bn2bin() to convert BIGNUM to array of unsigned char and send it over socket using send(). But what the client receives is corrupted. Why?
Here's a minimal working sample:
server.cpp
#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <cstdlib>
#include <openssl/bn.h>
using namespace std;
int main() {
// Set up
int result;
int opt_val = 1;
int port = 12345;
int listen_sock;
int peer_sock;
struct sockaddr_in address;
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = INADDR_ANY;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
result = bind(listen_sock, (struct sockaddr*)&address, sizeof(address));
if (result != 0) {
cerr << "bind() failed." << endl;
exit(result);
}
result = listen(listen_sock, 5);
if (result != 0) {
cerr << "listen() failed." << endl;
exit(result);
}
size_t size = sizeof(address);
peer_sock = accept(listen_sock, (struct sockaddr*)&address, (socklen_t *)&size);
if (peer_sock < 0) {
cerr << "accept() failed." << endl;
exit(result);
}
////////////////////////////////
// Prepare BIGNUM
BIGNUM* bn = BN_new();
BN_rand(bn, 1024, 0, 0);
size = BN_num_bytes((const BIGNUM*)bn);
// Send using fixed array
unsigned char fixed[size];
BN_bn2bin((const BIGNUM*)bn, fixed);
// Send using dynamic array
unsigned char *dynamic;
dynamic = new unsigned char[size];
BN_bn2bin((const BIGNUM*)bn, dynamic);
// First let's compare
if ( memcmp(fixed, dynamic, size) != 0) {
cout << "Fixed and dynamic do not equal" << endl;
exit(-1);
}
// Then let's send two arrays
send(peer_sock, &size, sizeof(size), MSG_MORE);
send(peer_sock, fixed, size, MSG_MORE);
send(peer_sock, dynamic, size, MSG_MORE);
}
client.cpp
#include <netinet/in.h>
#include <iostream>
#include <netdb.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <openssl/bn.h>
#include <cstring>
using namespace std;
int main() {
struct addrinfo* res;
struct sockaddr_in address;
int peer_port = 12345;
int self_sock;
string peer_ip = "127.0.0.1";
address.sin_family = AF_INET;
address.sin_port = htons(peer_port);
int result = getaddrinfo((const char*)peer_ip.c_str(), NULL, NULL, &res);
if (result != 0) {
std::cerr << "Peer hostname invalid." << std::endl;
exit(-1);
}
freeaddrinfo(res);
inet_pton(AF_INET, (const char*)peer_ip.c_str(), &(address.sin_addr));
self_sock = socket(AF_INET, SOCK_STREAM, 0);
if (::connect(self_sock, (struct sockaddr*)&address, sizeof(address)) != 0) {
std::cerr << "connect() failed." << std::endl;
exit(-1);
}
int size;
recv(self_sock, &size, sizeof(size), 0);
// Receive fixed array
unsigned char fixed[size];
unsigned char* dynamic = new unsigned char[size];
recv(self_sock, fixed, size, 0);
recv(self_sock, dynamic, size, 0);
if (memcmp(fixed, dynamic, size) != 0) {
cerr << "client: fixed and dynamic are different!" << endl;
exit(-1);
}
BIGNUM* bn_fixed = BN_new();
BIGNUM* bn_dynamic = BN_new();
BN_bin2bn((const unsigned char*)fixed, size, bn_fixed);
BN_bin2bn((const unsigned char*)dynamic, size, bn_dynamic);
if (BN_cmp((const BIGNUM*)bn_fixed, (const BIGNUM*)bn_dynamic) != 0) {
cerr << "bn_fixed and bn_dynamic are different!" << endl;
exit(-1);
}
return 0;
}
Build both with g++ -o <server/client> <server.cpp/client.cpp> -lssl -lcrypto
I used memcmp and verified that the memeory fixed and dynamic points to are equal to one another, but the fixed and dynamic client receives are totally different from each other and the original message. I doubt that it could be because I am using localhost, but when I tried using two independent machines it still happens.