I am using a tcp server that I wrote for handling inputs into a database. I have a tcp client sitting on a server that sends the filename to a tcp server sitting on a different linux server. once the filename is received the linux server goes into a shared folder and pulls the file then inserts it into the database.
my problem is with correctly declaring the buffer and clearing it to make sure I get the correct filename without any gibberish added or anything removed from it.
right now it is working like this:
char data[1024];
which is fine but it does not automatically delete the buffer completely, so i tried to implicitly allocate memory to "data" such as:
char *data = (char*) malloc(1024 * sizeof(char));
...
free(data);
OR
char *data = new char[1024];
...
delete[] data;
For some reason the above two declaration are declaring a buffer of size =8 I got this using
sizeof(data);
also what I am receiving is only 8 characters long. I am not sure why it is doing this, any help??
EDIT
char *data = (char*)malloc(1048 * sizeof(char));
if(data==NULL) exit(1);
cout << "DATA Size: " << sizeof(data) << "\n";
int msglen = read(conn, data, sizeof(data));
cout << "Server got " << msglen << " byte message: " << data << "\n";
if(write(conn, &msglen, sizeof(msglen))<0){
cout << "Failed to write back to the client " << strerror(errno);
}
free(data);
close(conn);
There are several things wrong with your code.
1) dont use malloc - you flagged your question as c++ - use malloc only when necessary replace it with:
const int dataSize = 1024;
char *data = new char[dataSize];
2) sizeof(data) when data is char* returns 8 because it returns size of a pointer not an array when you declare data as array sizeof will return bytes occupied by whole array. you should replace you read with:
int msglen = read(conn,data,dataSize)
3) I assume that u want to write data u've just received back to sender.. Then:
in write function you put sizeof(msglen) as third argument which will (mostly) always return 4. remove sizeof( ).
write(conn, data, msglen);
after you are done with the data dont forget to clear the memory using:
delete[] data;
use delete[] always when you assigned memory with new[].
API write(int socket, char *buf, int len);
Code becomes this:
write(con, data, msglen);
Assuming you can't use the stack (e.g. char buf[1024]), using naked pointers is discouraged as bad style and bug prone. Instead, use RAII and some variant of amanged memory, such as shared_ptr or unique_ptr.
#include <memory> and use a std::shared_ptr<>, or std::unique_ptr<> plus std::move() to return the buffer:
std::size_t bufSize = 1024;
std::unique_ptr<char[]> myUniqueBuf(new char[bufSize]);
ssize_t msglen = ::read(conn, *myUniqueBuf, bufSize); // return type is ssize_t, not int
return std::move(myUniqueBuf); // If you need to return the buffer
// I think you will probably prefer a shared_ptr<> because it has a copy
// constructor which makes it easier to pass around and return from functions
std::shared_ptr<char[]> mySharedBuf(new char[1024]);
ssize_t msglen = ::read(conn, *mySharedBuf, bufSize); // return type is ssize_t, not int
ssize_t bytesOut = ::write(conn, *mySharedBuf, msglen);
return mySharedBuf;
The advantage to std::shared_ptr or std::unique_ptr is that you don't have to worry about cleaning up a naked pointer (i.e. calling delete[] data;) because with managed memory it will happen automatically for you when the buffer handle goes out of scope or the reference count goes to zero (e.g. myUniqueBuf or mySharedBuf).
Related
I am creating a program that can get package and print it to console by C++.
I set the char array to 1024 like :
char* buffer = new char[1024];
When I get a message is not exactly 1024 character, there is many unknown character on the end of my message because of the empty space in the array. What can I do?
More information (I dont know if it is useful)
The socket is sent by a Java program
Socket socket = new Socket("127.0.0.1", 27555);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("I am your client :D");
out.flush();
And the server is written by C++ console application
char* recvData = new char[1024];
recv(socket, recvData, strlen(recvData), 0);
cout << recvData << endl;
There are three problems with the code:
recvData is unitialised when passed to strlen(). strlen() determines the length of the buffer when it finds a null terminating character, which could be within the buffer or outside. The size of the buffer, less one for terminating null character, should be passed as the maximum number of bytes to read.
the result of recv() is not queried. The code will use recvData even if the recv() failed, which is a bug.
recv() does not null terminate the buffer.
Save the result of recv() and if not -1 use it as an index into recvData to insert the null terminating character.
Alternatively, as this is c++ use a std::vector<char> and to manage dynamic memory allocation for you (if dynamic memory allocation is really required):
std::vector<char> recvData(1025); // Default initializes all elements to 0.
int result = recv(socket, recvData.data(), recvData.size() - 1);
if (result != -1)
{
std::cout << recvData.data() << std::endl;
}
Remember that data sent via sockets it just a stream of bytes, it is not separated into distinct messages. This means that:
out.write("I am your client :D");
might not be read by a single call to recv(). Equally:
out.write("I am your client :D");
out.write("OK");
might be read by a single call to recv(). It is the programmer's responsibility to implement a protocol if message-based processing is required.
strlen counts the number of bytes until a null ('\0') character is encountered. There is no guarantee that data returned by a single recv call wil be nul-terminated so you'll need to check the number of bytes returned then add your own terminator.
char* recvData = new char[1024];
int bytes = recv(socket, recvData, 1023, 0);
if (bytes == -1) {
cout << "error on recv" << endl;
}
else {
recvData[bytes] = '\0';
cout << recvData << endl;
}
recvData is not null terminated, so result of strlen() is undefined in this case. you have to do something like the following:
int len = 1024;
char *recvData = new char[len + 1];
int lenRead = recv(socket, recvData, len, 0);
if (lenRead < len)
recvData[lenRead] = '\0';
else
recvData[len] = '\0';
cout << recvData << endl;
Isn't this obvious? :)
Just send the length of the string first or terminate the string "properly" (by sending a \0 after the end of your string; I guess that's something Java isn't doing here).
But overall, you should include the "packet length" anyway, because you might want to ensure there's enough free space before writing to the buffer (using strlen() on an uninitialized array is usually a bad idea).
I been working in a project that handles some char* pointers, and it's a requisite of the class to use char* instead of std::string, so...
I have this structure definition and this queue:
typedef struct packetQueue
{
char* buf;
int length;
packetQueue()
{
buf = new char[];
length = 0;
}
} PACKET;
concurrency::concurrent_queue IP_in_queue;
I have this buffer:
char sendBuf[MSG_SIZE + sizeof (IP_PACKET_HEADER_T) + 1]; // String to be send
and a structure for my new buffer:
PACKET ipQueue;
then I fill my buffer with this:
// Concatenates the header with sended message
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);
ipQueue.buf = sendBuf;
ipQueue.length = packetSize;
And then I push my packet to my queue
IP_in_queue.push(ipQueue); // Push the buffer in the IP_in_queue
This is my loop just in case:
while ( 1 )
{
// Get the user input
cout << "> ";
cin.getline (buf, BUFLEN);
IP_PACKET_HEADER_T sendHeader; // Store the header to be send
PACKET ipQueue;
char* fakeIPAddressDst, *readMessage;
delay = atoi(strtok (buf," ")); // Takes the first delay value
fakeIPAddressDst = strtok (NULL, " "); // Stores the IP Address
readMessage = strtok (NULL, " "); // Stores the sended message
Sleep(delay); // Sleep the miliseconds defined
// Fills the header with the data neccesary data
sendHeader.DIP = inet_addr(fakeIPAddressDst);
sendHeader.SIP = inet_addr(initAddress.fakeIpAddress);
sendHeader.length = getStringLength(readMessage) + 1;
packetSize = sizeof( sendHeader ) + sendHeader.length; // Defines the size of the packet to be send
// Concatenates the header with sended message
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);
ipQueue.buf = sendBuf;
ipQueue.length = packetSize;
numbytes = packetSize; // The number of bytes of sended buffer
char sendedString[BUFLEN + 1]; // Variable for stores the data
IP_PACKET_HEADER_T readHeader; // To store the header for showing the information
// Print out the content of the packet
// Copy from buf to the header
memcpy( (void*)&readHeader, ipQueue.buf, sizeof( IP_PACKET_HEADER_T));
// Copy message part
memcpy( sendedString, &ipQueue.buf[sizeof(IP_PACKET_HEADER_T)], numbytes - sizeof(IP_PACKET_HEADER_T));
// Append \0 to the end
sendedString[numbytes - sizeof(IP_PACKET_HEADER_T)] = '\0';
// Save the IP information of the packet in a struct for print on the screen
struct in_addr fakeAddrHost;
fakeAddrHost.s_addr = readHeader.SIP;
// Print the neccesary data
cout << "[IN] DST: " << fakeIPAddressDst << endl; // Fake IP address of the destination
cout << "[IN] SRC: " << inet_ntoa(fakeAddrHost) << endl; // Fake IP address of the host
cout << "[IN] MSG: " << sendedString << endl ; // Message to send
IP_in_queue.push(ipQueue); // Push the buffer in the IP_in_queue
}
I know there is a memory leak in this procedure but I'm not sure.
When I push my packet, the buf pointer keeps pointing to my sendBuf, am I right? Because the assignment does that, but if I delete my pointer in the ipQueue after I push the program crashes. I have to say, after I push that struct into the queue, another thread try to pop that one, and obviously if I delete my ipQueue pointer I'll lost my buffer, so how can I avoid this memory leak?
Thanks
EDIT:
The memory leak using the definition of buf = nullptr
---------- Block 1 at 0x0068BB30: 264 bytes ----------
Call Stack:
d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (402): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::_Allocate_page + 0xF bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (113): MSVCP110D.dll!Concurrency::details::_Micro_queue::_Push + 0xD bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (232): MSVCP110D.dll!Concurrency::details::_Concurrent_queue_base_v4::_Internal_push
d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (566): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::push + 0xF bytes
d:\users\silex rpr\documents\visual studio 2012\projects\project2\project2\host.cpp (802): Host.exe!main
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): Host.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): Host.exe!mainCRTStartup
0x7662339A (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x77179EF2 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x77179EC5 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
First off; this isn't C, you're using a C++ compiler. structures in C cannot have methods and constructors and new and delete don't exist.
Secondly, you allocate memory for buf in your constructor, but then...
ipQueue.buf = sendBuf;
That's a leak. You need to call delete for every call to new. You allocate buf with new, but never call delete on it, so that memory is leaked.
I see no reason to allocate buf here. Just set it to null.
typedef struct packetQueue
{
char* buf;
int length;
packetQueue()
: buf(nullptr), length(0) { }
} PACKET;
On a side note, this is a very nasty mix of C and C++. Is this what your teacher is teaching you guys?
You've got a class (structure) with a constructor that allocates memory and no destructor that releases it, so you get memory leaks.
You also expose the buf member and assign to it; so your class has no control over whether the memory should be freed or not. But you need to free the memory allocated in the constructor before you assign to the buf the first time.
To get this right, you'll need to make the buf field private and add a destructor, a copy constructor and an assignment operator (and probably an accessor function). You'll still not be exception safe, though.
The problem you have is that you haven't looked at copy construction and copy assignment: when you push an object into a std::vector<T> it gets copied and the objects with the std::vector<T> get possibly moved around using assignment. The default generated copy constructor and copy assignment just copy or assign the respective members, i.e., whenever either copy is used, you'd end up with two objects pointing to the same buf. The first one destroyed would use delete[] buf; and all others would have a stale pointer which can't be deleted again. That is, you want to add three methods to your packetQueue:
struct packetQueue
{
packetQueue(packetQueue const& other); // copy constructor: copies the content
packetQueue& operator= (packetQueue const& other); //copy assignment: updates the content
~packetQueue() // destructor: release the memory
void swap(packetQueue& other); // swap the content
// other members
};
To leverage the copy construction and destruction in the copy assignment, I find it useful to have a swap() member, because this is easily implemented and makes for a nice, simple copy assignment:
void packetQueue::swap(packetQueue& other) {
std::swap(this->buf, other.buf);
std::Swap(this->size, other.size);
}
packetQueue& packetQueue::operator= (packetQueue const& other) {
packetQueue(other).swap(*this);
return *this;
}
I am experimenting with the HTTP protocol using Winsock2. I am working on a function
int recv_data(const char *hostname, char *resp);
The function is meant to send an HTTP HEAD request to a given host and then receive a response. It allocated memory at the pointer resp and copies the response there before returning the total number of bytes received for the response.
Here is my recieve loop:
int recv_data(const char *hostname, char *resp)
{
int totalRecvd = 0;
stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
resp = new char[totalRecvd + 1];
strcpy(resp, sStream.str().c_str());
return totalRecvd);
}
All of this works just fine and all and if I output resp at this point it outputs just fine. I just have a problem if I try to output resp after the function has returned apparently. I do not believe this should be how things normally go and if I am not mistaken I believe it has something to do with me using the stringstream to temporarily store the response. I think I have read somewhere about the data that stringstream collects going out of scope.
I was hoping that I could have this function set up this way where the caller can just pass in a char* and the function will allocate the correct amount of memory (which is determined at runtime depending on the host and the number of bytes returned by recv(). Is there anyway for me to get a permanent copy from a stringstream in memory as a char array with the pointer being bad after the function returns and the stringstream goes out of scope?
[EDIT]: Here is the solution posted below incorporated into my problem, anyone looking to reuse this for Winsock2 proramming have at it, seems to work well. Will recv data from the server until the connection is closed when recv() returns 0. The solution is passing in a reference to the pointer, because the new operator changes the pointer and that change is not reflected after the function returns unless it is passed in by reference.
int recv_data(SOCKET s, char *&data)
{
int totalRecvd = 0;
std::stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
data = new char[totalRecvd + 1];
strcpy_s(data, totalRecvd, sStream.str().c_str());
data[totalRecvd] = 0;
return totalRecvd;
}
resp is a local variable in the http_req function. Updating the value of resp will have no effect outside of http_req. This line:
resp = new char[totalRecvd + 1];
will have only local effect.
Try this signature:
int http_req(const char *hostname, char *&resp);
Even better, try returning the data in a C++ way:
std::string http_req(const std::string& hostname) {
...
return sStream.str()
}
If you alter your code to use std::string and boost::asio, you will no longer suffer from memory management problems.
I am working on network programming using epoll and I have this code.
int str_len = read(m_events[i].data.fd, buf, BUF_SIZE);
printf("read %d \n", str_len);
if(str_len == 0){
if(!removeClient(m_events[i].data.fd))
break;
close(m_events[i].data.fd);
}
else {
printf("ServerManager::eventAcceptLoop, A message has been received \n");
pushWork(buf);
}
the buf is declared like this
buf[BUF_SIZE];
and I want to pass the data in the buf to the functiion "pushWork"
pushWork(char * pdata){
hand this pdata to the thread pool to parse and handle it
}
I think I need to copy the data in the buf instead of pointing to the buf because it will be overriden whenever a new data comes in. Right now I do something like
char *pdata = buf;
pushWork(pdata)
Should I do memcopy or something else? and flush the buf?
Please let me know how I can handle this. Thanks in advance...
Yes, you can copy the data:
char* pdata = new char[str_len];
memcpy(pdata, buf, str_len);
pushWork(pdata);
At the pushWork end, it has to take care of freeing the data when it's done:
delete[] pdata;
You will also want to consider encapsulating this all into a std::vector so you don't have to worry about exception safety:
std::vector<char> data(buf, buf + str_len);
pushWork(data);
In this case, pushWork needs to be modified to take a std::vector by value, but the upside is that it won't have to worry about deleting the data when done, and will be fully exception-safe.
I am trying to get the entire raw header into a file but everytime I attempt to write the contents I get a file full of ÌÌÌÌÌÌÌÌÌÌÌ. What am I doing wrong?
DWORD CTryISAPIFilter::OnPreprocHeaders(CHttpFilterContext* httpContext,
PHTTP_FILTER_PREPROC_HEADERS headerInformation)
{
char buffer[4096];
DWORD bufferSize = sizeof(buffer);
BOOL HeaderBoolean = headerInformation->GetHeader(httpContext->m_pFC, "ALL_RAW", buffer, &bufferSize);
char * ptrIn = (char *) buffer;
std::string postData2 = ptrIn;
char * outputString = new char[4096];
int i = 0;
for(i=0;i<4096;i++){
outputString[i] = postData2[i];
}
outputString[i+1] = NULL;
std::ofstream outfile ("D:\\WebSites\\wwwroot\\test.txt",std::ios::app);
outfile << outputString << std::endl;
outfile.close();
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
Is headerInformation->GetHeader() returning success?
If so, how much is it actually writing into buffer (presumably it tells you this in a value it places in bufferSize)
I suspect that GetHeader() is failing, and nothing is being written to buffer because:
you're getting all "ÌÌÌÌÌÌÌÌÌÌÌ" characters (which is what the debug builds of VC will set uninitialized memory to), and
you're not getting an exception thrown when you index postData2 well past what should usually be the end of the string (in most cases anyway). So there's apparently no '\0' terminator in buffer (which GetHeader() will write if it succeeds).
You need to check for this failure and examine GetLastError() to get more information on what the failure is.
Update: Your buffer might not be large enough. See http://msdn.microsoft.com/en-us/magazine/cc163939.aspx for how to appropriately size the buffer.
Update 2: It's been a while since I've done web stuff, but isn't "ALL_RAW" a CGI-style server environment variable rather than a header? Shouldn't you retrieve this using GetServerVariable() instead of GetHeader()?