i was working on a socket server on a friend's computer and everythng was working fine but then i executed the code on my computer and it throws a buffer overflow like this
*** buffer overflow detected ***: /home/erick/CLionProjects/AirWar++/cmake-build-debug/AirWar__ terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f906c5047e5]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7f906c5a556c]
/lib/x86_64-linux-gnu/libc.so.6(+0x116570)[0x7f906c5a3570]
/lib/x86_64-linux-gnu/libc.so.6(+0x1169da)[0x7f906c5a39da]
We are using rapidjson library to send the data, i dont know why this happens if the exact same code runs perfectly on his computer, the only difference is that i am running Ubuntu on a VM and he was running Ubuntu as the main OS.
I would really appreciate your help, the code fails on this if:
if ((valread = read( sd , buffer, 1024)) == 0)
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[3] ,
max_clients = 3 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
void server::init() {
using namespace rapidjson;
char buffer[400];
//set of socket descriptors
fd_set readfds;
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.100.19");//Write your IP
address.sin_port = htons( PORT );
//bind the socket to localhost port 8080
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Escuchando en el puerto %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Esperando conexiones ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number
printf("Nueva conexion , socket fd %d , ip : %s , puerto : %d\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs
(address.sin_port));
//send new connection message
//if( send(new_socket, "Conectado", strlen("Conectado"), 0) != strlen("Conectado") )
//{
// perror("send");
//}
//puts("Mensaje enviado con exito");//succesfully send
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("AƱadido a la lista de sockets como %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and read the message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , \
(socklen_t*)&addrlen);
printf("Cliente desconectado , ip %s , port %d \n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
run=FALSE;
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//se eliminan dos caracteres nulos del buffer;
std::string m=buffer;
std::string s(m.substr(0,valread));
const char * json= s.c_str();
std::cout<<json;
Document d;
d.Parse(json);
Value& type=d["type"];
if(strcmp(type.GetString(),"shoot")==0){
stat= 5;//Dispara
}else if(strcmp(type.GetString(),"izq")==0){
//Mov. izquierda
stat= 4;
}else if(strcmp(type.GetString(),"der")==0){
//Mov. derecha
stat=6;
}else if(strcmp(type.GetString(),"arr")==0){
//Mov. arriba
stat=8;
}else if(strcmp(type.GetString(),"aba")==0){
//Mov. abajo
stat= 2;
}else{
stat=0;//Quieta
}
}
}
}
}
}
long server:: Send(const char * msg){
send(client_socket[0],msg,strlen(msg),0);
}
Btw we both use CLion.
Will be waiting for your help, thanks!
char buffer[400];
// ^^^
...
if ((valread = read( sd , buffer, 1024)) == 0)
// ^^^^
I hate to sound like a jerk, but didn't the error message prompt you to check the size of buffers that you were reading data into?
Also note that with TCP reads you might not get the entire message in a read() call so buffer might not be null terminated which can cause problems here:
std::string m=buffer;
And this line makes me think that the null terminator might not even be part of the message (we'd have to see the client code to be sure):
send(client_socket[0],msg,strlen(msg),0);
Buffer overflow is exactly what it is.
if ((valread = read( sd , buffer, 1024)) == 0)
Here you are lying to the operating system about the size of buffer, which is 400, not 1024. This line of code should be
if ((valread = read( sd , buffer, sizeof buffer)) == 0)
and you also need to check it for -1.
Related
Hi everyone i have a little problem, i supposed to transfer a file from a server( a tcp server with threads to a client). The problems appers at the end of transmision the file is recived by client but it stucks and I can't longer communicate with it.
This is the server
int main(int argc, char *argv[])
{
int socket_desc, client_sock, c;
struct sockaddr_in server, client;
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2025);
//Bind
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc, 5);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
int enable = 1;
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while ((client_sock = accept(socket_desc,
(struct sockaddr *) &client,
(socklen_t*) &c)))
{
puts("Connection accepted");
if (setsockopt(client_sock,
SOL_SOCKET,
SO_REUSEADDR,
&enable,
sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
if (pthread_create(&thread_id,
NULL,
connection_handler,
(void*) &client_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
pthread_join(thread_id, NULL);
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
void *connection_handler(void *socket_desc)
{
printf("Enter in handler");
//Get the socket descriptor
int sock = *(int*) socket_desc;
send_problemo(sock);
return 0;
}
This is the sending function where I think is the real problem
int send_problemo(int *sock)
{
ssize_t read_return;
char *file_path = "Problems/1.txt";
char buffer[BUFSIZ];
int filefd;
filefd = open(file_path, O_RDONLY);
char end[2] = "1";
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
while (1)
{
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
{
printf("este 0 \n");
break;
}
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(sock, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
}
// close(sock);
close(filefd);
}
The client is connecting normally and receives the file in this function
int recive_problemo(int *sockfd)
{
char *file_path = "path.c";
char buffer[BUFSIZ];
ssize_t read_return;
int filefd;
filefd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
do
{
read_return = read(sockfd, buffer, BUFSIZ);
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
} while (read_return > 0);
close(filefd);
}
I kind of managed how to solve this. If i shutdown(SHUT_WR) from server the client isnt stuck anymore, but i want to communicate with it further.
Also with the same function if i transfer from client to server, it works perfectly, so can anyone help me please?
do
{
read_return = read(sockfd, buffer, BUFSIZ);
// error handling
// file write
} while (read_return > 0);
Will keep looping until the socket closes or there's an error. It has no way to tell if a file has finished.
Common solutions are to close the socket (but you don't want that) and establish a communication protocol so that you know when the file is done and can exit the loop.
To keep things very simple, I recommend sending the length of the file before sending the file. The loop now looks something like:
uint64_t file_len;
read_return = recv(sockfd, &file_len, sizeof(file_len), MSG_WAITALL);
if (read_return == sizeof(file_len))
{
// Strongly consider handling the endian of file_len here
while (file_len)
{
size_t readmax = std::min(file_len, BUFSIZ);
read_return = read(sockfd, buffer, readmax);
if (read_return > 0)
{
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
file_len -= read_return;
}
else
{
// handle error
// exit loop if not recoverable
}
}
}
The server end picks up the responsibility of getting and sending the length of the file. I won't get into that because there are too many different ways to get the length of a file. Pick your favourite.
Documentation on recv and MSG_WAITALL.
I have a problem in case of multiple clients socket programming in c++. Actually I have downloaded a source code for server side that echo the message to the clients. Also I have a simple client code. Everything works perfectly as long as there is only one client connected to the server. But when the other client connects, the server echo the message to both of them but, in the client side it prints in different order. Indeed it wait for user to enter the input message and then print out the received message. But I want it to be print it as soon as the message is received. For better description of the problem, the output of chat between two clients connected to the server is mentioned bellow. Also the codes of server and client are attached at the end.
in the Bob cmd:
Pleas insert your message: Bob: hello alice.
The recieved message:Bob: hello alice.
Pleas insert your message: Bob: how is everything?
The recieved message:Alice: hello bob.
Pleas insert your message: Bob: everything is perfect!
The recieved message:Bob: how is everything?Alice: it is fine, and you?
Pleas insert your message:
in the alice cmd:
Pleas insert your message: Alice: hello bob.
The recieved message:Bob: hello alice.
Pleas insert your message: Alice: it is fine, and you?
The recieved message:Alice: hello bob.Bob: how is everything?
Pleas insert your message: Alice: cool!
The recieved message:Alice: it is fine, and you?Bob: everything is perfect!
Pleas insert your message:
and the codes:
/*
TCP Echo server example in winsock
Live Server on port 8888
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET master , new_socket , client_socket[30] , s;
struct sockaddr_in server, address;
int max_clients = 30 , activity, addrlen, i, valread;
//size of our receive buffer, this is string length.
int MAXRECV = 1024;
//set of socket descriptors
fd_set readfds;
//1 extra for null character, string termination
char *buffer;
char msg[10] = "salam";
buffer = (char*) malloc((MAXRECV + 1) * sizeof(char));
for(i = 0 ; i < 30;i++)
{
client_socket[i] = 0;
}
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//Create a socket
if((master = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(master ,(struct sockaddr *)&server , sizeof(server)) ==
SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//Listen to incoming connections
listen(master , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
addrlen = sizeof(struct sockaddr_in);
while(TRUE)
{
//clear the socket fd set
FD_ZERO(&readfds);
//add master socket to fd set
FD_SET(master, &readfds);
//add child sockets to fd set
for ( i = 0 ; i < max_clients ; i++)
{
s = client_socket[i];
if(s > 0)
{
FD_SET( s , &readfds);
}
}
//wait for an activity on any of the sockets, timeout is NULL , so wait
indefinitely
activity = select( 0 , &readfds , NULL , NULL , NULL);
if ( activity == SOCKET_ERROR )
{
printf("select call failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master , &readfds))
{
if ((new_socket = accept(master , (struct sockaddr *)&address, (int *)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//send( new_socket , msg , valread , 0 );
send( new_socket, msg, (int)strlen(msg), 0 );
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
if (client_socket[i] == 0)
{
client_socket[i] = new_socket;
printf("Adding to list of sockets at index %d \n" , i);
break;
}
}
}
//else its some IO operation on some other socket :)
for (i = 0; i < max_clients; i++)
{
s = client_socket[i];
//if client presend in read sockets
if (FD_ISSET( s , &readfds))
{
//get details of the client
getpeername(s , (struct sockaddr*)&address , (int*)&addrlen);
//Check if it was for closing , and also read the incoming message
//recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one).
valread = recv( s , buffer, MAXRECV, 0);
if( valread == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if(error_code == WSAECONNRESET)
{
//Somebody disconnected , get his details and print
printf("Host disconnected unexpectedly , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket( s );
client_socket[i] = 0;
}
else
{
printf("recv failed with error code : %d" , error_code);
}
}
if ( valread == 0)
{
//Somebody disconnected , get his details and print
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket( s );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//add null character, if you want to use with printf/puts or other string handling functions
buffer[valread] = '\0';
printf("%s:%d - %s \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port), buffer);
//for (int j=0;j<4;j++) {
send( client_socket[0] , buffer , valread , 0 );
send( client_socket[1] , buffer , valread , 0 );
//printf("%d",client_socket[j]);
//}
memset(buffer,'\0',sizeof(buffer));
}
}
}
}
closesocket(s);
WSACleanup();
return 0;
}
/*
* Client
*
* Created on: May 31, 2017
* Author: Bamshad
*/
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x501
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "8888"
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char sendbuf[1000];
char recvbuf[DEFAULT_BUFLEN];
int iResult, activity;
int recvbuflen = DEFAULT_BUFLEN;
// Validate the parameters
if (argc != 2) {
printf("usage: %s server-name\n", argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
//printf("%d\n",ConnectSocket);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
while(TRUE) {
cout << "Lotfan paiam khod ra vared konid: ";
cin.getline(sendbuf,1000);
send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
memset(sendbuf,'\0',sizeof(sendbuf));
recv(ConnectSocket, recvbuf, recvbuflen, 0);
cout << "paiam dariaft:" << recvbuf <<endl;
memset(recvbuf,'\0',sizeof(recvbuf));
}
return 0;
}
I also tried the following code in client side. But still it does not work!
while(TRUE) {
FD_ZERO(&fds); //Clearing the set of descriptors
//FD_SET(fileno(stdin), &fds); //Adding Keyboard to set of descriptors
FD_SET(ConnectSocket,&fds); //Adding Socket to the set of descriptors
activity = select( 0 , &fds , NULL , NULL , NULL);
if ( activity == SOCKET_ERROR )
{
printf("select call failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
if(FD_ISSET(ConnectSocket,&fds)) {
recv(ConnectSocket, recvbuf, recvbuflen, 0);
cout << "paiam dariaft:" << recvbuf <<endl;
memset(recvbuf,'\0',sizeof(recvbuf));
fflush(stdout);
}
//looking if there is user input from keyboard (0 is for stdin)
if(!_kbhit()) {
//fflush(stdout);
cin.getline(sendbuf,1000);
send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
memset(sendbuf,'\0',sizeof(sendbuf));
}
So I'm writing a very basic TCP server which just echoes back the messages sent from the client back to the client. I have a setup where the server is running in a while loop and waiting for either a new client to connect or for a message from one of the existing clients using the select() method.
My question is:
How do i, from the server side, close the master socket and basically shutting down the server. Im not asking for exact code but more for standard practice.
For some context:
In the long run I am imagining multiple clients connected to my server and I need to shutdown the server gracefully from the server side.
Even more context: The server code.
#define TRUE 1
#define FALSE 0
#define PORT 55555
int main(int argc, char* argv[])
{
int opt = TRUE;
int masterSocket, addrlen, newSocket, maxClients = 10, clientSockets[maxClients],
activity, valread, sd, maxSd;
struct sockaddr_in address;
char buffer[1025];
fd_set readfds;
const char *message = "ECHO DAMON v1.0 \r\n";
/* Initialize array with 0 so it's not read */
for(int i = 0; i < maxClients ; i++)
{
clientSockets[i] = 0;
}
/* Create master socket */
if((masterSocket = socket(AF_INET, SOCK_STREAM,0)) == 0)
{
perror("Error when trying to create master socket.\n");
exit(EXIT_FAILURE);
}
/* Set master socket to allow multiple connections */
if( setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)
{
perror("Could not set sockopt");
exit(EXIT_FAILURE);
}
/* Socket type */
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if( bind(masterSocket, (struct sockaddr*)&address, sizeof(address)) < 0)
{
perror("Error, could not bind master socket. \n");
exit(EXIT_FAILURE);
}
printf("Listening on %d. \n", PORT);
if( listen(masterSocket, 3) < 0)
{
perror("Error, could not listen.\n");
exit(EXIT_FAILURE);
}
addrlen = sizeof(address);
puts("Waiting for connections...\n"); //just a printf variant
/* END INIT */
while(TRUE)
{
/* Clear socket set */
FD_ZERO(&readfds);
/* Add master socket to set */
FD_SET(masterSocket, &readfds);
/* Add child sockets to set, will be 0 first iteration */
for(int i = 0; i < maxClients ; i++)
{
sd = clientSockets[i]; // sd = socket descriptor
/* If valid socket descriptor */
if(sd > 0)
{
FD_SET(sd, &readfds);
}
/* Get highest fd number, needed for the select function (later) */
if(sd > maxSd)
{
maxSd = sd;
}
}//end for-loop
/* Wait for activity on any socket */
activity = select(maxSd +1, &readfds, NULL, NULL, NULL);
if((activity < 0) && (errno != EINTR))
{
printf("Error on select.\n"); //no need for exit.
}
/* If the bit for the file descriptor fd is set in the
file descriptor set pointed to by fdset */
/* If something happend in the master socket, its a new connection */
if(FD_ISSET(masterSocket, &readfds))
{
if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
{
perror("Could not accept new socket.\n");
exit(EXIT_FAILURE);
}
/* Print info about connector */
printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
if( send(newSocket, message, strlen(message), 0) != strlen(message))
{
perror("Could not sent welcome message to new socket.\n");
}
puts("Welcome message sen successfully.\n");
/* Add new socket to array of clients */
for(int i = 0; i < maxClients; i++)
{
if(clientSockets[i] == 0)
{
clientSockets[i] = newSocket;
printf("Adding socket to list of client at index %d\n", i);
break;
}
}
}//end masterSocket if
/* Else something happend at client side */
for(int i = 0; i < maxClients; i++)
{
sd = clientSockets[i];
if(FD_ISSET(sd, &readfds))
{ /* Read socket, if it was closing, else read value */
if((valread = read( sd, buffer, 1024)) == 0)
{
getpeername( sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
close(sd);
clientSockets[i] = 0;
}
}
else
{
buffer[valread] = '\0';
send(sd, buffer, strlen(buffer), 0);
}
}
}
return 0;
}
If you are planning to exit your application gracefully by adding a breakstatement in your app by something similar to this:
if (exit_condition)
{
break;
}
You can place this loop at the end of your main function:
/* close connections gracefully */
closesocket(masterSocket);
masterSocket = 0; /* optional, see comment below */
for(int i = 0; i < maxClients; i++)
{
if (clientSockets[i] != 0)
{
shutdown(clientSockets[i]);
closesocket(clientSockets[i]);
clientSockets[i] = 0; /* optional, except if you also have a SIGINT handler */
}
}
If you want to do the same to handle an exit with Ctrl-C, you will find details on how to setup a SIGINT handler to handle Ctr-C here:
Catch Ctrl-C in C. Place the above loop in your handler, then. Your sockets-related variables will have to be declared at global scope, since your sockets are only visible from main() in your current code.
Here is my client-server code which works only for a single user at a time and the client can send as many messages as he wants.
I show the received message at the server and its reply (which is actually reverse of it) - and also the message "message sent".
At client side I show the input message and the server reply: "message got"
But there is a problem in my code: when I try to send multiple messages I get the right output at server side but not at client side, which is only "message got", but after that puts function it doesn't print any output to std-out. I have tried many things but I haven't found a way to do it.
Is there any flushing to std-out or am I missing something?
Please tell me.
server code::::::
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char client_message[2000];
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 42969 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while(1)
{
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
pid_t p=fork();
if(p==0)
{
close(socket_desc);
//Receive a message from client
while( (read_size = recv(client_sock , client_message , sizeof(client_message) , 0)) > 0 )
{
puts(client_message);
char message[20000];
int i,j=0;
for(i=strlen(client_message)-1;i>=0;i--)
message[j++]=client_message[i];
message[j]='\0';
puts(message);
//Send the message back to client
if( send(client_sock , message , sizeof(message),0)>0)
puts("message sent");
// memset(client_message,'\0',sizeof(client_message));
//memset(message,'\0',sizeof(message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
close(client_sock);
exit(1);
}
}
close(socket_desc);
return 0;
}
client code::::
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
// char message[1000] ,
char server_reply[2000];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons (42969 );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
//keep communicating with server
while(1)
{
printf("Enter message : ");
char message[1000];
scanf("%s" , message);
//Send some data
if( send(sock , message , sizeof(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
//Receive a reply from the server
if( recv(sock , server_reply , sizeof(server_reply) , 0) > 0)
{
puts("message got");
}
puts("Server reply :");
puts(server_reply);
fflush(stdout);
//memset(server_reply,'\0',sizeof(server_reply));
// memset(message,'\0',sizeof(message));
}
close(sock);
return 0;
}
There are different flaws in this code.
Server side:
you accept socket client_sock in a loop, but only close it in the child: you are leaking socket descriptors -> parent should have also close(client_sock);
client send a message of max size 1000, that server reads in a buffer of size 2000. Fine till here. But you use strlen to find the useful part and send back 2000 bytes (meaning you are sending garbage).
Client side:
you read a string from stdin with scanf into a buffer or size 1000. Ok. But then you send 1000 byte, the message and garbage.
you have no message delimitation. So first message could need many read (in fact if needs at least 2 since you currently send 2000 bytes and read it by chunks of 1000!)
You are mixing size of buffer, string length, and number of bytes sent/received. In server, you should use the number of bytes received and never output more then it, of if you know the the message is null terinated, never output more than its length. And if you want to exchange more than one message, use a delimiting strategy (ending with null (uncommon) or with \n, of send first one or 2 bytes containing the size).
You have problem at this place in server side code:
if( send(client_sock , message , sizeof(message),0)>0)
puts("message sent");
You must replace:
if( send(client_sock , message , strlen(message) + 1,0)>0)
puts("message sent");
I have a client(c++) / server(c) program and currently I'm having difficulty communicating between them (I can't see what the client says on the server and vice versa). Also I am trying have this project multi-threaded, or at least accept multiple connections from clients. All help is greatly appreciated here is the code pertaining to chatting, you can view it in its entirety here
client:
recv(sockfd , server_reply , 2000 , 0);
puts("Enter message :"); // asking for password
scanf("%s" , message);
send(sockfd , message , strlen(message) , 0);
recv(sockfd, server_reply, 2000, 0);
//Receive a reply from the server
if( recv(sockfd , server_reply , 2000 , 0) < 0)
{
puts("recv failed");
}
while( (read_size = recv(nsockfd , server_reply , 4000 , 0)) != 0)
{
puts("Enter message :"); // asking for password
scanf("%s" , message);
send(sockfd , message , strlen(message) , 0);
recv(sockfd, server_reply, 2000, 0);
}
Server
char client_address[90];
sprintf(client_address, "Welcome %s", inet_ntoa(addr_remote.sin_addr));
char welc_msg[90] = "Welcome %s";
char friend_msg[50] = "Hello little friend \n";
char username[30] = "Enter user:";
char pass[30] = "Enter pass: ";
write(nsockfd , client_address , strlen(client_address)); // attempting to send client "Hello, (their ip address)"
read_size = recv(nsockfd , client_message , 4000 , 0);
read_size = recv(nsockfd , client_message , 4000 , 0);
printf( "%s", client_message);
printf( "\n");
//Receive a message from client
while( 1 ) // while( (read_size = recv(nsockfd , client_message , 4000 , 0)) != 0)
{
//clearing buffer
memset(client_message, 0, sizeof(client_message));
//taking received message and printing it
read_size = recv(nsockfd , client_message , 4000 , 0);
printf( "%s", client_message);
printf( "\n");
//Send the message back to client
// write(nsockfd , server_message , strlen(server_message));
if (strcmp(client_message , "Hello")) // condition for project
{
write(nsockfd, friend_msg, strlen(friend_msg));
}
}
When you call the system functions, always check for errors! Where relevant, also check for partial writes / receives. For example, when you have this line:
send(sockfd , message , strlen(message) , 0);
You should have something like this (untested, so think it through yourself):
(Edit: removed unnecessary resend loop to simplify code. See edit history if you want to see it...)
int msglen = strlen(message);
fprintf(stderr, "debug: about to send %d bytes", msglen);
int sent = send(sockfd , message , msglen , 0);
if (sent == -1) { // for each function, read docs for error result
perror("send message");
// do some error handling
} else if (sent < msglen) {
fprintf(stderr, "debug: partial send %d/%d\n", sent, msglen);
// do some disconnect handling
}
Once you have proper error reporing, and if you can't solve your problem with that, then update the question with this debug/error information.
Try this code:
Server.c
while (1) {
//---- ACCEPT connection ------------------------------------
sa = accept(s, 0, 0); // block for connection request
if (sa < 0) {
printf("accept error %ld ", WSAGetLastError() );
WSACleanup();
return false;
}
else {
printf("connection accepted");
}
/* gets(buf);
bytesSent = send( s, buf, 10, 0 );
printf( "Bytes Sent: %ld \n", bytesSent );*/
//------------------------------------------------------------
// Socket is now set up and bound. Wait for connection and process it.
//---- RECV bytes --------------------------------------------
bytesRecv = recv( sa, recvbuf, 10, 0 );
err = WSAGetLastError( );// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call)
if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {
printf( "Connection Closed.\n");
WSACleanup();
}
printf( "\nBytes Recv from Client: %s \n ", recvbuf );
//-------------------------------------------------------------
// if(bytesRecv != 0 || bytesRecv != WSAECONNRESET){
bytesSent = send( sa, buf, 10, 0 );
if(bytesSent == -1)
{
//break;
puts("Error\n");
}
else
{
printf( "Bytes Sent: %ld \n", bytesSent );
Sleep(1000);
}
closesocket( sa );
}
Client.c
while(1) {
//--- INITIALIZATION -----------------------------------
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
printf("WSAStartup error %ld", WSAGetLastError() );
WSACleanup();
return false;
}
//------------------------------------------------------
//---- Build address structure to bind to socket.--------
target.sin_family = AF_INET; // address family Internet
target.sin_port = htons (SERVER_PORT); //Port to connect on
target.sin_addr.s_addr = inet_addr (IPAddress); //Target IP
//--------------------------------------------------------
// ---- create SOCKET--------------------------------------
s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
if (s == INVALID_SOCKET)
{
printf("socket error %ld" , WSAGetLastError() );
WSACleanup();
return false; //Couldn't create the socket
}
//---------------------------------------------------------
//---- try CONNECT -----------------------------------------
if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
printf("connect error %ld", WSAGetLastError() );
WSACleanup();
return false; //Couldn't connect
}
//-----------------------------------------------------------
//---- SEND bytes -------------------------------------------
bytesSent = send( s, buf, 10, 0 );
printf( "Bytes Sent: %ld \n", bytesSent );
Sleep(1000);
if((bytesRecv = recv( s, recvbuf, 10, 0 )) == SOCKET_ERROR)
{
puts("Socket Error");
err = WSAGetLastError( );// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call)
}
else
{
if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {
printf( "Connection Closed.\n");
WSACleanup();
}
printf( "\nBytes Recv from Server: %s \n ", recvbuf );
//closesocket( sa );
}
//------------------------------------------------------------
closesocket( s );
WSACleanup();
}
The above code strictly for Windows.