I am trying to send a file to a server using socket programming. My server and client are able to connect to each other successfully however I am expecting the while loop below to go through the entire file and add it to the server. The issue I am having is that it only send the first chunk and not the rest.
On the client side I have the following:
memset(szbuffer, 0, sizeof(szbuffer)); //Initialize the buffer to zero
int file_block_size;
while ((file_block_size = fread(szbuffer, sizeof(char), 256, file)) > 0){
if (send(s, szbuffer, file_block_size, 0) < 0){
throw "Error: failed to send file";
exit(1);
} //Loop while there is still contents in the file
memset(szbuffer, 0, sizeof(szbuffer)); //Reset the buffer to zero
}
On the server side I have the following:
while (1)
{
FD_SET(s, &readfds); //always check the listener
if (!(outfds = select(infds, &readfds, NULL, NULL, tp))) {}
else if (outfds == SOCKET_ERROR) throw "failure in Select";
else if (FD_ISSET(s, &readfds)) cout << "got a connection request" << endl;
//Found a connection request, try to accept.
if ((s1 = accept(s, &ca.generic, &calen)) == INVALID_SOCKET)
throw "Couldn't accept connection\n";
//Connection request accepted.
cout << "accepted connection from " << inet_ntoa(ca.ca_in.sin_addr) << ":"
<< hex << htons(ca.ca_in.sin_port) << endl;
//Fill in szbuffer from accepted request.
while (szbuffer > 0){
if ((ibytesrecv = recv(s1, szbuffer, 256, 0)) == SOCKET_ERROR)
throw "Receive error in server program\n";
//Print reciept of successful message.
cout << "This is the message from client: " << szbuffer << endl;
File.open("test.txt", ofstream::out | ofstream::app);
File << szbuffer;
File.close();
//Send to Client the received message (echo it back).
ibufferlen = strlen(szbuffer);
if ((ibytessent = send(s1, szbuffer, ibufferlen, 0)) == SOCKET_ERROR)
throw "error in send in server program\n";
else cout << "Echo message:" << szbuffer << endl;
}
}//wait loop
} //try loop
The code above is the setup for the connection between the client and server which works great. It is in a constant while loop waiting to receive new requests. The issue is with my buffer. Once I send the first buffer over, the next one doesn't seem to go through. Does anyone know what I can do to set the server to receive more than just one buffer? I've tried a while loop but did not get any luck.
Your code that sends the file from the server appears to send consecutive sections of the file correctly.
Your code that appears to have the intention of receiving the file from the client performs the following steps:
1) Wait for and accept a socket.
2) Read up to 256 bytes from the socket.
3) Write those bytes back to the socket.
At this point the code appears to go back to waiting for another connection, and keeping the original connection open, and, at least based on the code you posted, obviously leaking the file descriptor.
So, the issues seems to be that the client and the server disagreeing on what should happen. The client tries to send the entire file, and doesn't read from the socket. The server reads the first 256 bytes from the socket, and writes it back to the client.
Of course, its entirely possible that portions of the code not shown implement some of the missing pieces, but there's definitely a disconnect here between what the sending side is doing, and what the receiving side is doing.
buffer will only send once to the server
No, your server is only reading once from the client. You have to loop, just like the sending loop does.
Related
This is on an AS400 (IBM i, iSeries, et al).
I have a small Java program that I use to send test files to a server written in C++, which also runs on the IBM i. In my Java program I am setting my timeout for a response to be 5, lets say. In the server I am randomly sleeping for 0 to 10 seconds. When the Java program times out, it throws java.net.SocketTimeoutException, closes the socket with .close() and exits. The server program just goes ahead after its sleep and calls send(). Thing is, send() does not fail with -1 and give ENOTCONN. Why? Also inet_ntop() on the socket gives me the remote IP and port that connected to the server, as though the socket were still connected. Scratching my head.
EDIT: After disappointment with poll(), I found select() will report an error with FD_ISSET() when setting the errors set. In my case, select() returns 3, indicating that 3 conditions (read, write and error) are set for my one socket. You can't find out what the error is, at least I don't know yet how to find out.
fd_set read_set, write_set, error_set;
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_ZERO(&error_set);
FD_SET(sock_fd, &read_set);
FD_SET(sock_fd, &write_set);
FD_SET(sock_fd, &error_set);
struct timeval timeout;
timeout.tv_sec = 10; // reset this on every new iteration.
timeout.tv_usec = 0;
int rc = select(sock_fd + 1, &read_set, &write_set, &error_set, &timeout);
CERR << "select() returned " << rc << endl;
if (rc >= 0) {
if (FD_ISSET(sock_fd, &read_set)) {
CERR << "ready to read" << endl;
}
if (FD_ISSET(sock_fd, &write_set)) {
CERR << "ready to write" << endl;
}
if (FD_ISSET(sock_fd, &error_set)) {
CERR << "has an error" << endl;
CERR << "errno=" << errno << ", " << strerror(errno) << endl;
}
}
From man send:
ENOTCONN
The socket is not connected, and no target has been given.
In other words your expectations are incorrect. ENOTCONN is for the case when you haven't connected the socket. It doesn't have anything to do with the peer disconnecting. That case will eventually cause ECONNRESET, but not on the first such send, because of TCP buffering.
Working as designed.
I have written C++ client server application and the server is crashing.
The scenario
Start server
1 hour later (not before) Client connect
Then the Server which is waiting in accept returns -1 with errno "Too many open files".
Nothing else special is running on the machine which led me to believe that accept is opening many file descriptors while waiting.
Is that true?
How can I fix this so the client could connect anytime?
the relevant server code:
int sockClient;
while (true) {
sockaddr_in* clientSockAddr = new sockaddr_in();
socklen_t clientSockAddrLen = sizeof(sockaddr_in);
sockClient = accept(sockServer, (sockaddr *) clientSockAddr,
&clientSockAddrLen);
if(sockClient == -1 ){
std::ostringstream s;
s << "TCP Server: accept connection error." << std::strerror(errno);
throw runtime_error(s.str());
}
connection->communicate(sockClient, clientSockAddr, clientSockAddrLen);
}
You have a file descriptor leak somewhere. Possibly you aren't closing accepted sockets when you've finished with them, or else it's on a file somewhere.
I have used C++ & Winsock2 to create both server and client applications. It currently handles multiple client connections by creating separate threads.
Two clients connect to the server. After both have connected, I need to send a message ONLY to the first client which connected, then wait until a response has been received, send a separate message to the second client.
The trouble is, I don't know how I can target the first client which connected.
The code I have at the moment accepts two connections but the message is sent to client 2.
Can someone please give me so ideas on how I can use Send() to a specific client? Thanks
Code which accepts the connections and starts the new threads
SOCKET TempSock = SOCKET_ERROR; // create a socket called Tempsock and assign it the value of SOCKET_ERROR
while (TempSock == SOCKET_ERROR && numCC !=2) // Until a client has connected, wait for client connections
{
cout << "Waiting for clients to connect...\n\n";
while ((ClientSocket = accept(Socket, NULL, NULL)))
{
// Create a new thread for the accepted client (also pass the accepted client socket).
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID);
}
}
ClientSession()
unsigned __stdcall ClientSession(void *data)
{
SOCKET ClientSocket = (SOCKET)data;
numCC ++; // increment the number of connected clients
cout << "Clients Connected: " << numCC << endl << endl; // output number of clients currently connected to the server
if (numCC <2)
{
cout << "Waiting for additional clients to connect...\n\n";
}
if (numCC ==2)
{
SendRender(); // ONLY TO CLIENT 1???????????
// wait for client render to complete and receive Done message back
memset(bufferReply, 0, 999); // set the memory of the buffer
int inDataLength = recv(ClientSocket,bufferReply,1000,0); // receive data from the server and store in the buffer
response = bufferReply; // assign contents of buffer to string var 'message'
cout << response << ". " << "Client 1 Render Cycle complete.\n\n";
SendRender(); // ONLY TO CLIENT 2????????????
}
return 0;
}
Sendrender() function (sends render command to the client)
int SendRender()
{
// Create message to send to client which will initialise rendering
char *szMessage = "Render";
// Send the Render message to the first client
iSendResult = send(ClientSocket, szMessage, strlen(szMessage), 0); // HOW TO SEND ONLY TO CLIENT 1???
if (iSendResult == SOCKET_ERROR)
{
// Display error if unable to send message
cout << "Failed to send message to Client " << numCC << ": ", WSAGetLastError();
closesocket(Socket);
WSACleanup();
return 1;
}
// notify user that Render command has been sent
cout << "Render command sent to Client " << numCC << endl << endl;
return 0;
}
You can provide both a wait function and a control function to the thread by adding a WaitForSingleObject (or WaitForMultipleObjects) call. Those API calls suspend the thread until some other thread sets an event handle. The API return value tells you which event handle was set, which you can use to determine which action to take.
Use a different event handle for each thread. To pass it in to a thread you will need a struct that contains both the event handle and the socket handle you are passing now. Passing a pointer to this struct into the thread is a way to, in effect, pass two parameters.
Your main thread will need to use CreateEvent to initialize the thread handles. Then after both sockets are connected it would set one event (SetEvent), triggering the first thread.
A am writing a client-server program in C. It sends a directory name and receives a list of files as answer. The problem I have is that it gets stuck in an infinite loop.
If I send only one directory name it works, but if I send a list of directories it never ends and outputs nothing.
Server
while(recv(sock, name, BUFSIZE, 0) > 0){
if ((fddir=opendir(name)) == NULL){
send(sock, strerror(errno), strlen(strerror(errno)), 0);
close(sock);
return 1;
}
send(sock, name, strlen(name), 0);
send(sock, ":", strlen(":"), 0);
send(sock, "\n", strlen("\n"), 0);
while ((dirbuf = readdir(fddir)) != NULL){
buf[0] = '\0';
strcat(buf, dirbuf->d_name);
strcat(buf, "\t");
send(sock, buf, BUFSIZE, 0);
}
}
Client
for (int i=1;i<3;i++){
send(sock, argv[i], strlen(path), 0);
while(recv(sock, buf, BUFSIZE, 0) > 0)
printf("%s", buf);
}
The server waits until all directory names are received, and then the client wait until server send all files in it. How do I trace where the program gets stuck?
TCP is not message based, so you have no way of knowing where the boundaries between two client send() calls is when you call recv() on the server. Thus when you send multiple names back-to-back it is possible for the server to receive them all in a single recv() (or however many bytes you allocated for BUFSIZE). This is probably mangling your directory names, causing opendir to fail. This would be more obvious to you if you were checking for errors from send and recv and Captain Obvlious describes in another answer.
You need to check the calls to recv for errors. It returns 0 if the connection was disconnected and -1 on an error. You are only checking for values > 0 which will not work. The example below shows how to approach checking the errors.
while(true)
{
const int result = recv(sock, buf, BUFSIZE, 0);l
if(result == -1)
{
std::cout << "Error: " << errno << std::endl;
break;
}
else if(result == 0)
{
std::cout << "Disconnected" << std::endl;
break;
}
// process the data here. No errors
}
You should also be checking the value returned by send as it works in the same way.
I am uncertain about a few things regarding ftp file transfer. I am writing an ftp server and I am trying to figure out how to make the file tranfer work correctly. So far it works somehow but I have certain doubts. Here is my file transfer function (only retrieve so far):
void RETRCommand(int & clie_sock, int & c_data_sock, char buffer[]){
ifstream file; //clie_sock is used for commands and c_data_sock for data transfer
char *file_name, packet[PACKET_SIZE]; //packet size is 2040
int packet_len, pre_pos = 0, file_end;
file_name = new char[strlen(buffer + 5)];
strcpy(file_name, buffer + 5);
sprintf(buffer, "150 Opening BINARY mode data connection for file transfer\r\n");
if (send(clie_sock, buffer, strlen(buffer), 0) == -1) {
perror("Error while writing ");
close(clie_sock);
exit(1);
}
cout << "sent: " << buffer << endl;
file_name[strlen(file_name) - 2] = '\0';
file.open(file_name, ios::in | ios::binary);
if (file.is_open()) {
file.seekg(0, file.end);
file_end = (int) file.tellg();
file.seekg(0, file.beg);
while(file.good()){
pre_pos = file.tellg();
file.read(packet, PACKET_SIZE);
if ((int) file.tellg() == -1)
packet_len = file_end - pre_pos;
else
packet_len = PACKET_SIZE;
if (send(c_data_sock, packet, packet_len, 0) == -1) {
perror("Error while writing ");
close(clie_sock);
exit(1);
}
cout << "sent some data" << endl;
}
}
else {
sprintf(buffer, "550 Requested action not taken. File unavailable\r\n", packet);
if (send(clie_sock, buffer, packet_len + 2, 0) == -1) {
perror("Error while writing ");
close(clie_sock);
exit(1);
}
cout << "sent: " << buffer << endl;
delete(file_name);
return;
}
sprintf(buffer, "226 Transfer complete\r\n");
if (send(clie_sock, buffer, strlen(buffer), 0) == -1) {
perror("Error while writing ");
close(clie_sock);
exit(1);
}
cout << "sent: " << buffer << endl;
close(c_data_sock);
delete(file_name);
}
So one problem is the data transfer itself. I am not exactly sure how it is supposed to work. Now it works like this: the server sends all the data to c_data_sock, closes this socket and then the client starts doing something. Shouldn't the client recieve the data while the server is sending them? And the other problem is the abor command. How am I supposed to recieve the abor command? I tried recv with flag set to MSG_OOB but then I get an error saying "Invalid argument". I would be glad if someone could give me a hint or an example of how to do it right as I don't seem to be able to figure it out myself.
Thanks,
John
Ftp use two connections. First - is command connection, in your case it is clie_sock. 'ABOR' command should be received though it. You going to receive it the same way you received 'RETR' command.
To receive file client establishes data connection with your server ( c_data_sock socket ). It will not be opened till client connects, so this is the answer to your second question. You cannot start client after server executes this function. First client sends 'retr' command to your command socket. Then your sever waits new connection from client ( after sending him data ip and port ). Then client connects ( now you have your c_data_sock ready ) and sends all the data to that socket, which are in turn received by the client.
You probably need to read more about networking in general if you feel you don't understand it. I prefer this one: http://beej.us/guide/bgnet/
Also you have a memory leak here, after you allocate an array with the
file_name = new char[strlen(buffer + 5)];
you need to delete it using
delete [] file_name;
Otherwise file_name will be treated as a simple pointer, not an array, so most of array memory will be kept by your application which is bad especially when creating server.