I am writing a client-server solution. The goal is to connect to a camera remotely and receive its camera feed in the client. I am using TCP protocol for this. Yes, this is the first time I'm doing this.
The client is written in Java. This means it uses BufferedReader.readLine(). Yes, the problem is that it results in null and I am aware that this means that the server shuts down the connection. I have also had this confirmed by a senior coder.
The server is written in C. My problem is that I cannot find an obvious reason to why its code results in shutting down the connection seemingly immediately. I have found multiple code-examples that supports the method I'm already using.
I wonder:
Here is my original server code (see update below it):
#define _GNU_SOURCE -D
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <syslog.h>
#include <capture.h>
#include <sys/sendfile.h>
#include <pthread.h>
//define where the network camera is located
#define PORT_NUMBER 80
#define SERVER_ADDRESS "localhost"
void *msg_handler(void *);
//step 1
/* The server is supposed to send a list of available resolutions and frames per second, so the client can choose*/
//we create a handler to each client
void *client_handler(int server_socket)
{
int serverSocket = *(int *)server_socket; // this is a pointer to the server socket
char *message, cli_message[40000];
message = capture_get_resolutions_list(0); //list of available image resolutions;
write(serverSocket, message, strlen(message)); //send to client the list of resolutions
write(serverSocket, "\n", strlen("\n")); //breaking line so the client can see the list
memset(message, 0, strlen(message)); //resetting the message variable
//variables related to the image
media_stream *imageStream;
recv(serverSocket, cli_message, 40000, 0); // receive information from client regarding resolution
media_frame *imageFrame;
void *data;
size_t imageSize;
int arrayRow = 0; //related to the data array - we need it if we want to loop later through the array
//opening the stream in order to capture image
imageStream = capture_open_stream(IMAGE_JPEG, cli_message);
//send image to client with chosen resolution
while (1) //condition always true, i.e. infinite loop
{
imageFrame = capture_get_frame(imageStream);
data = capture_frame_data(imageFrame);
imageSize = capture_frame_size(imageFrame);
sprintf(message, "%zu\n", imageSize); //converting the size to a char , and send to client
write(serverSocket, message, strlen(message)); //sending the size to the client
unsigned char arrayRow_data[imageSize];
for (arrayRow = 0; arrayRow < imageSize; arrayRow++)
{
arrayRow_data[arrayRow] = ((unsigned char *)data)[arrayRow];
}
//try to send data to client ---> see the possible errors
int sendDataError = write(serverSocket, arrayRow_data, sizeof(arrayRow_data));
if (sendDataError < 0)
{
syslog(LOG_INFO, "oops, connection with client lost");
break;
}
//restoring variables to ZERO
memset(data, 0, sizeof(data));
memset(arrayRow_data, 0, sizeof(arrayRow_data));
capture_frame_free(imageFrame);
}
syslog(LOG_INFO, "ERROR:CAN NOT SEND IMAGE");
capture_close_stream(imageStream);
close(serverSocket);
return 0;
}
//main function
//creating a socket
int main(void)
{
//char server_message[256]= "Congrats, you have reached the server";
int server_socket;
int client_socket;
int *new_socket;
int conn;
struct sockaddr_in server, client;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(1025);
//bind the socket to the specified IP and port
bind(server_socket, (struct sockaddr *)&server, sizeof(server));
conn = sizeof(struct sockaddr_in);
listen(server_socket, 5);
//accept the connection from the client and send the message
while ((client_socket = accept(server_socket, (struct sockaddr *)&client, (socklen_t *)&conn)))
{
pthread_t client_thread;
new_socket = malloc(sizeof *new_socket);
new_socket = client_socket;
//establishing a message thread and possible errors
if (pthread_create(&client_thread, NULL, client_handler, (void *)new_socket) < 0)
{
syslog(LOG_INFO, "ERROR. MESSAGE THREAD NOT ESTABLISHED");
return 1;
}
}
if (client_socket < 0)
{
syslog(LOG_INFO, "Sorry, client socket declined");
free(new_socket);
return 1;
}
return 0;
}
Here's an UPDATED server code. It has a lot of comments because we want to keep track of what we've done for now. Still the same problem:
#define _GNU_SOURCE -D
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <syslog.h>
#include <capture.h>
#include <sys/sendfile.h>
#include <pthread.h>
//define where the network camera is located
#define PORT_NUMBER 443
#define SERVER_ADDRESS "localhost"
//store recieved messages from client
//char cli_message;
//This is a buffer to store a welcome message to client in.
char buffer[1024];
char *message; //declared like this instead.
void * client_handler(void *server_socket) //This probably had the wrong input variable.
{
//int serverSocket = (int) (intptr_t)server_socket;
int new_socket = (int)(intptr_t) (server_socket); // this is a pointer to the server socket.
//char *message, cli_message[2000];
//HERE: get the media_stream BEFORE trying to fetch message
media_stream *imageStream;
media_frame *imageFrame;
//ADDED: storing the image data.
char *imageData;
//ADDED: storing the size of the image data array.
size_t imgSize;
//MOVED and changed from server_socket
recv(new_socket, message, 2000, 0); // receive information from client regarding resolution
//MOVED. NOW we get the available resolutions.
message = capture_get_resolutions_list(0); //list of available image resolutions;
//ADDED: Fetching the length of message in an int to make CERTAIN it's right and using a different method later in write to send it.
int first_message_size = strlen(message);
//write(serverSocket, message, strlen(message));
write(new_socket, message, first_message_size); //send to client the list of resolutions
write(new_socket, "\n", strlen("\n")); //breaking line so the client can see the list
memset(message, 0, strlen(message)); //resetting the message variable
//Store the recieved resolution and FPS from client picked by user.
recv(new_socket, message, 2000, 0);
//opening the stream in order to capture image
imageStream = capture_open_stream(IMAGE_JPEG, message);
//send image to client with chosen resolution
while (1) //condition always true, i.e. infinite loop
{
imageFrame = capture_get_frame(imageStream);
imageData = capture_frame_data(imageFrame);
imgSize = capture_frame_size(imageFrame);
sprintf(message, "%zu\n", imgSize); //converting the size to a char , and send to client
write(new_socket, message, strlen(message)); //sending the size to the client
//EDITED: sends image data to client, we also check if this write fails. We send imgSize, not sizeof(data).
int sending = write(new_socket, imageData, imgSize);
//Here we check that it's sending. If it isn't, the problem might be
//that the CLIENT disconnected.
if (sending < 0)
{
syslog(LOG_INFO, "ERROR! Failed to send. Client disconnected?");
break;
}
//EDITED: Another reset of variables cause we DO NOT want to store this.
memset(imageData, 0, sizeof(imageData));
//memset(arrayRow_data, 0, sizeof(arrayRow_data));
capture_frame_free(imageFrame);
//unsigned char arrayRow_data[imgSize];
int arrayRow;
for (arrayRow = 0; arrayRow < imgSize; arrayRow++)
{
imageData[imgSize] = imageData[arrayRow];
}
}//End of while
syslog(LOG_INFO, "Exiting...");
capture_close_stream(imageStream);
close(new_socket);
//ADDED
pthread_exit(NULL);
return 0;
}
int start(void)
{
//(might solve our log issues)
openlog ("server", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
//message onto server log
syslog(LOG_INFO, "Server running...");
//char server_message[256]= "Congrats, you have reached the server";
int server_socket;
int new_socket;
//int *new_socket;
//int conn; //wat is dis?
//struct sockaddr_in server, client;
struct sockaddr_in server;
struct sockaddr_storage storage; //This is new. Testing.
socklen_t addressLength;
server_socket = socket(PF_INET, SOCK_STREAM, 0); //Changed to PF
server.sin_family = AF_INET;
server.sin_port = htons(443);
server.sin_addr.s_addr = htonl(INADDR_ANY);//we added htons & htonl
//Deal with eventual padding field
memset(server.sin_zero, '\0', sizeof server.sin_zero);
//bind the socket to the specified IP and port
bind(server_socket, (struct sockaddr *) &server, sizeof(server));
//conn = sizeof(struct sockaddr_in); ----> wat is?
//Gave the listener a few more helpers. Longer time and max 40 con
//requests.
if(listen(server_socket, 50)==0)
{
syslog(LOG_INFO, "Listening\n");
}
else
{
syslog(LOG_INFO, "Not listening, lalalala.\n");
}
pthread_t client_thread[60]; //Move to outside of loop and given size.
int i = 0; //used in the if-statement in the below while-loop.
int end = 1; //used to end the while-loop.
//accept the connection from the client and send the message
while(end)
{
addressLength = sizeof storage;
//new_socket = malloc(sizeof *new_socket);
//new_socket = accept(server_socket, (struct sockaddr *) &client, (socklen_t *)&conn);
*new_socket = accept(server_socket, (struct sockaddr *) &storage, &addressLength); //New addition
//establishing a message thread and possible errors
//if(pthread_create(&client_thread, NULL, client_handler, (void *)((intptr_t) new_socket))< 0)
//Trying this if-statement instead..
if(pthread_create(&client_thread[i], NULL,client_handler,(void *)((intptr_t) new_socket)) != 0)
{
syslog(LOG_INFO, "ERROR. MESSAGE THREAD NOT ESTABLISHED!");
}
i++;
if( i > 50)
{
end = 0;
}
}
return 0;
}
//end
This turned out to be a case of the cameras used not being properly configured for remote access (something not under my control)!
I'm still thankfull for all the tips and pointers given. But for the future, if anyone encounters the same issues and it feels impossible to solve, here's a few tips: