I m writing a chat application (client & server) using C in VS 2010.
I have finished writing my code as you can see below but there is still a problem.
This problem is that the client doesn't receive on time the messages that server sends.
Server code :
#include <WinSock2.h>
#include <stdio.h>
#include <time.h>
main()
{
SOCKET ListeningSocket;
SOCKET AcceptSocket;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
WSADATA wsaData;
const unsigned short PORT = 4444;
FD_SET fdread;
FD_SET BackUpfdread;
FD_SET fdwrite;
FD_SET BackUpfdwrite;
int maxDescriptor;
SOCKET SocketArray[20];
int index = 0;
int selectResults;
int i,k;
int clientAddrSize;
int RecvBytes;
int SentBytes;
char SentBuff[500];
char RecvBuff[500];
struct timeval timeout;
// Initialize Winsock2.2
WSAStartup(MAKEWORD(2,2),&wsaData);
// Initialize Listening Socket
ListeningSocket = socket(AF_INET,SOCK_STREAM,0);
// Initialize ServerAddr
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
ServerAddr.sin_port = htons(PORT);
// Bind the ServerAddr with ListeningSocket
bind(ListeningSocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
// Listening Socket
listen(ListeningSocket,5);
FD_ZERO(&fdread);
FD_ZERO(&BackUpfdread);
FD_ZERO(&fdwrite);
FD_ZERO(&BackUpfdwrite);
// Asign ListeningSocket at fdread
FD_SET(ListeningSocket,&fdread);
maxDescriptor = ListeningSocket;
SocketArray[index] = ListeningSocket;
index++;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
// Main loop starts here
for(; ;)
{
BackUpfdread = fdread;
BackUpfdwrite = fdwrite;
selectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);
//printf("server select() OK\n");
if(selectResults == -1)
{
printf("Select() error");
WSACleanup();
return 0;
}
for(i=0;i<=index-1;i++)
{
//printf("%d\n",SocketArray[i]);
if(FD_ISSET(SocketArray[i],&BackUpfdread))
{
if(SocketArray[i] == ListeningSocket) // we have a new connection
{
clientAddrSize = sizeof(ClientAddr);
AcceptSocket = accept(ListeningSocket,(SOCKADDR *)&ClientAddr,&clientAddrSize);
// Add the newest accepted socket to the fdread and fdwrite sets.
FD_SET(AcceptSocket,&fdread);
FD_SET(AcceptSocket,&fdwrite);
// Add the newest accepted socket into SocketArray
SocketArray[index] = AcceptSocket;
index++;
// keep track of the maxDescriptor.
if(AcceptSocket > maxDescriptor)
{
maxDescriptor = AcceptSocket;
}
printf("New connection from %s on socket %d\n", inet_ntoa(ClientAddr.sin_addr), AcceptSocket);
}else{ // That means that the socket is not from a new conection and has something sent.
memset(RecvBuff,0,sizeof(RecvBuff));
RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff)-1, 0);
if(RecvBytes > 0) // Some data received.
{
printf("Message Sent.\n");
printf("Message was: %s\n",RecvBuff);
for(k=0;k<=index-1;k++)
{
if(SocketArray[k] != ListeningSocket && SocketArray[k] != SocketArray[i])
{
memset(SentBuff,0,sizeof(SentBuff));
strcpy(SentBuff,RecvBuff);
SentBytes = send(SocketArray[k],SentBuff,sizeof(SentBuff),0);
if(SentBytes > 0)
{
printf("Message Forwarded\n");
}else{
printf("Message forward error\n");
}
}
}
}
}
}
}
SleepEx(10, FALSE);
}// Main loop ends here
}
Client code :
#include <WinSock2.h>
#include <stdio.h>
#include <time.h>
main()
{
SOCKET ConnectSocket;
SOCKET SocketArray[20];
SOCKADDR_IN ServerAddr;
WSADATA wsaData;
FD_SET fdwrite;
FD_SET fdread;
FD_SET BackUpfdread;
FD_SET BackUpfdwrite;
char server_address[20] = "192.168.1.4";
char SentBuff[500];
char RecvBuff[500];
const unsigned short PORT = 4444;
int maxDescriptor;
int index = 0;
int SelectResults;
int i;
int RecvBytes;
int SentBytes;
BOOL bOpt = TRUE;
struct timeval timeout;
// Initialize Winsock 2.2
WSAStartup(MAKEWORD(2,2),&wsaData);
// Initialize ServerAddr
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(server_address);
ServerAddr.sin_port = htons(PORT);
// Create a new socket to make a client connection.
ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
setsockopt(ConnectSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&bOpt,sizeof(BOOL));
// Clear the fd sets
FD_ZERO(&fdread);
FD_ZERO(&BackUpfdread);
FD_ZERO(&fdwrite);
FD_ZERO(&BackUpfdwrite);
// Asign ConnectSocket into fdread and fdwrite.
FD_SET(ConnectSocket,&fdread);
FD_SET(ConnectSocket,&fdwrite);
// Set timer
timeout.tv_sec = 0;
timeout.tv_usec = 0;
maxDescriptor = ConnectSocket;
SocketArray[index] = ConnectSocket;
index++;
// Make a connection to the server with socket s.
if(connect(ConnectSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
printf("Couldn't connect to the server\n");
}
// Main loop starts here
for(; ;)
{
BackUpfdread = fdread;
BackUpfdwrite = fdwrite;
memset(SentBuff, 0, sizeof(SentBuff));
printf("Write: ");
gets_s(SentBuff, sizeof(SentBuff));
SelectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);
for(i=0;i<=index-1;i++)
{
// Something to read from server.
if(FD_ISSET(SocketArray[i],&BackUpfdread) && SocketArray[i] == ConnectSocket)
{
RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff), 0);
if(RecvBytes > 0)
{
printf("%s\n",RecvBuff);
// Cleaning the Receive Buffer
memset(RecvBuff,0,sizeof(RecvBuff));
}
}
// Something to write.
if(FD_ISSET(SocketArray[i],&BackUpfdwrite) && SocketArray[i] == ConnectSocket)
{
SentBytes = send(SocketArray[i], SentBuff,sizeof(SentBuff),0);
// Cleaning the Sent Buffer
memset(SentBuff,0,sizeof(SentBuff));
}
}
SleepEx(10, FALSE);
} // Main menu ends here
}
In my opinion something seems not working good at clients side. I m telling this because if i use telnet application as client messages transferred correct.
Does anyone have an idea on how to fix this ?
Thanks
Just a wild guess: As you are using a hard coded ip-address:port tuple to access the server, are you sure it is the correct on?
Client 2 does not "... have to write something ..." to receive, but is blocked in gets_s() waiting for user input, and therefore cannot select() and therefore cannot recv().
To solve this blocking issue you can go for two approaches.
1 Mulit-threaded solution (more portable)
Change the client design to handle the server connection (writing to it and reading form it) asynchronously, for example in a different thread then the main thread.
2 Single-threaded solution (non-portable)
2.1 Windows
You can use ReadConsoleEvent() to implement non-blocking read from the console.
For example this could be done like this:
/*
* Does a non-blocking read of characters from the stdin into the
* buffer referenced by 'pszBuffer' up to a maximum of 'sizeBuffer'.
*
* If bEcho is TRUE the characters read are echoed to the console window.
*
* Returns the characters read or a negative value on error.
*/
DWORD ReadConsoleNonBlocking(char * pszBuffer, size_t sizeBuffer, BOOL bEcho)
{
DWORD dwRC = 0;
static HANDLE stdinHandle = 0;
stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
{
if (!pszBuffer)
return -1;
if (!sizeBuffer)
return -2;
{
INPUT_RECORD input = {0};
DWORD NumberOfEventsRead = 0;
if (!ReadConsoleInput(stdinHandle, &input, 1, &NumberOfEventsRead))
return -3;
if (NumberOfEventsRead && (KEY_EVENT == input.EventType) && input.Event.KeyEvent.bKeyDown)
{
DWORD dwCharactersRead = 0;
while (input.Event.KeyEvent.wRepeatCount > dwCharactersRead && dwCharactersRead < sizeBuffer)
{
pszBuffer[dwCharactersRead] = input.Event.KeyEvent.uChar.AsciiChar;
if ('\r' == pszBuffer[dwCharactersRead])
pszBuffer[dwCharactersRead] = '\n';
if (bEcho)
printf("%c", pszBuffer[dwCharactersRead]); /* echo character read to console */
++ dwCharactersRead;
}
dwRC = dwCharactersRead;
}
}
}
return dwRC;
}
2.2 UNIX
You can use the result of fileno(stdin) to retrieve the file descriptor for standard input and add it to the set of file descriptors passed to select() to be notified if something was entered via the console.
Related
I have main server code, which uses select and waits for hosts activities.
I have also global structure, which stores all clients and theirs sockets.
//old code
Select in main thread unblocks intself when one of the hosts from clients array disconnects. Then I try to read data, and when it is 0, client is disconnected. Why select in Thread doesn't work in the same way? It works perfect when clients exchange data, but there is no reaction, when one of clients disconnects.
EDIT.
Sorry I have previously posted the code, which could not be compiled. The idea was, just to get the information if my idea of clients handling is correct and if this idea should work. I have created simple example and now it works. So, I have to review my oryginal code.
Working example:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <pthread.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#define MAXCLIENTS 1000
#define FRAMESIZE 40
struct Client
{
int socket;
char state;
};
struct Client clients[2];
struct ThreadArgs
{
int srcClientIdx;
int dstClientIdx;
};
int portNumber=8090;
void * SocketThread(void *args)
{
printf("New thread created.\n");
struct ThreadArgs *threadArgs = (struct ThreadArgs*)args;
int sidx = threadArgs->srcClientIdx;
int didx = threadArgs->dstClientIdx;
int srcSocket = clients[sidx].socket;
int dstSocket = clients[didx].socket;
fd_set readfds;
struct timeval timeout;
while(1)
{
FD_ZERO(&readfds);
FD_SET(srcSocket, &readfds);
FD_SET(dstSocket, &readfds);
printf("Waiting for activities in thread.\n");
timeout.tv_sec = 60;
timeout.tv_usec = 0;
int activity = select(MAXCLIENTS+1, &readfds , NULL , NULL , &timeout);
if ((activity < 0) && (errno!=EINTR))
printf("Activity error.\n");
else if(activity == 0)
printf("Activity timeout.\n");
if (FD_ISSET(srcSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",sidx);
clients[sidx].state = 0;
clients[sidx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",sidx);
}
if (FD_ISSET(dstSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(dstSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",didx);
clients[didx].state = 0;
close(clients[didx].socket);
clients[didx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",didx);
}
}
}
int ConfigureTCPIPconnection(int socket,struct sockaddr_in *serverAddr)
{
// Address family = Internet
serverAddr->sin_family = AF_INET;
//Set port number, using htons function to use proper byte order
serverAddr->sin_port = htons(portNumber);
//Incoming addresses
serverAddr->sin_addr.s_addr = INADDR_ANY;
//Set all bits of the padding field to 0
memset(serverAddr->sin_zero, '\0', sizeof serverAddr->sin_zero);
//Bind the address struct to the socket
if(bind(socket, (struct sockaddr *)serverAddr, sizeof(struct sockaddr)) < 0)
{
printf("Binding failed. %s\n",strerror(errno));
return 1;
}
printf("Bind sucessfull.\n");
return 0;
}
int CheckSocketActivity(fd_set *readfds)
{
int activity = select( MAXCLIENTS + 1 , readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
fd_set readfds;
int serverSocket,newSocket;
pthread_t td; //thread descriptor
struct sockaddr_in serverAddr, newAddr={0};
socklen_t addr_size;
clients[0].state = 0;
clients[0].socket = -1;
clients[1].state = 0;
clients[1].socket = -1;
if((serverSocket = socket(PF_INET, SOCK_STREAM, 0)) == 0)
{
printf("Server socket creation failed.\n");
exit(1);
}
if(ConfigureTCPIPconnection(serverSocket,&serverAddr))
{
printf("Binding failed.\n");
exit(2);
}
if(listen(serverSocket,MAXCLIENTS))
{
printf("Listen error.\n");
exit(3);
}
printf("Listening...\n");
while(1)
{
FD_ZERO(&readfds); //clear fd set
FD_SET(serverSocket, &readfds); //add server socket to fd set
if(clients[0].state == 1)
FD_SET(clients[0].socket, &readfds); //add active clients to fd set
if(clients[1].state == 1)
FD_SET(clients[1].socket, &readfds);
printf("Waiting for activities.\n");
if(!CheckSocketActivity(&readfds))
{
if(FD_ISSET(serverSocket, &readfds))
{
if((newSocket = accept(serverSocket, (struct sockaddr *)&newAddr, (socklen_t*)&addr_size))<0) //create new socket
printf("New socket error. %s\n",strerror(errno));
else
{
printf("New socket connected.\n");
if(clients[0].state == 0)
{
printf("Client0 added.\n");
clients[0].state = 1;
clients[0].socket = newSocket;
}
else if(clients[1].state == 0)
{
printf("Client1 added.\n");
clients[1].state = 1;
clients[1].socket = newSocket;
}
}
}
else
{
for(int i=0;i<2;i++)
{
int srcSock = clients[i].socket;
if (FD_ISSET(srcSock, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSock, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",i);
clients[i].state = 0;
close(clients[i].socket);
clients[i].socket = -1;
}
else
{
if(clients[0].state == 1 && clients[1].state == 1)
{
int srcIndex,dstIndex;
//some other stuff
clients[0].state = 2;
clients[1].state = 2;
if(i == 0)
{
srcIndex = 0;
dstIndex = 1;
}
else
{
srcIndex = 1;
dstIndex = 0;
}
printf("Creating new thread.\n");
struct ThreadArgs threadArgs = {srcIndex,dstIndex};
if(pthread_create(&td, NULL, SocketThread, &threadArgs) != 0)
printf("Failed to create thread.\n");
if (pthread_detach(td))
printf("Thread detach error.\n");
}
else
printf("Two clients required for creating thread.\n");
}
}
}
}
}
}
}
I assume you posted the code you are indeed dealing with because the code you posted shouldn't compile.
Correction 1 (May not be the source of the problem)
From the select() man page:
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
All FD_*() macros take fd_set* argument. In the main() you have passed fd_set instead of fd_set* at few places.
Correction 2 (May be the source of the problem)
In SocketThread() this piece of code might be the cause of the issue:
if (FD_ISSET(dstSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
bytesCnt = read(srcSock, buffer, sizeof(buffer));
if(bytesCnt == 0)
**//this is not detected**
else
//any other activities are detected
}
You may probably want read(dstSocket, buffer, sizeof(buffer));.
You say:
Select in main thread unblocks intself when one of the hosts from clients array disconnects. Then I try to read data, and when it is 0, client is disconnected. Why select in Thread doesn't work in the same way? It works perfect when clients exchange data, but there is no reaction, when one of clients disconnects.
Please, you don't say how the client disconnects. Does it just close the socket? does it do a shutdown? I don't see any close(2) on the socket, so why do you know who is closing the connection (or calling shutdown(2) to indicate that no more data is going to appear in the connection)?
normally, a connection blocks until you receive some data... receiving 0 data means no data has arrived or, after a select(2) call has selected a socket descriptor that show no more data, then you have the socket closed. But this has to be closed somewhere, and you show neither close(2) nor shutdown(2). You also don't describe what is what is detected on the socket. If you awake from the select(2) you get to the file descriptor and the result from read is not 0 what value does the read return? have you got acquainted that -1 is one of such possible values, and that it means you have a readin error? Do you check the value returned by select? (on timeout, my memory tells me that select(0) returns 0, so are you checking for timeout?)
Please, next time, provide a complete and verifiable example. The code you post cannot be made to run without a huge amount of contribution, so the problem can only be reproduced on your side. Check this page for some reading about how to post code in StackOverflow.
I want to make a server software similar to Apache on windows platforms.
. The client sends data to the specified server port and the server responds accordingly. In order to improve the client access speed, I want to use "select" to improve the performance of the server, but there are many problems in the use process.
Here is my code;
Function "create_server"
This function is used to create the server Socket and set it to non-blocking.
int create_server(char*ip_address,int port) {
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
int server_socket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
int ret = -1;
struct sockaddr_in addr;
if (server_socket == -1) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr= INADDR_ANY;
ret = bind(server_socket,(LPSOCKADDR)&addr,sizeof(addr));
if (ret == -1) {
perror("bind error!");
return -2;
}
listen(server_socket,5);
SetBlock(server_socket, 0);
return server_socket;}
Function "SetBlock"
This function is used to change the socket blocking mode.
int SetBlock(int sock, int isblock){
int re = 0;
unsigned long ul = 0;
if (!isblock) ul = 1;
re = ioctlsocket(sock, FIONBIO, (unsigned long*)& ul);
if (re != 0) return 0;
return 1;
}
Function "main"
int main() {
int s = create_server("127.0.0.1",6666);
int client_socket = -1;
struct sockaddr_in clientaddr;
int addrlen = sizeof(clientaddr);
char buf[1025];
int buffersize=1,result=0;
int isread = 0;
fd_set server;
struct timeval timeout;
int fd = 0;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
FD_ZERO(&server);
FD_SET(s, &server);
while (1) {
result = select(FD_SETSIZE, &server, NULL, NULL, NULL);
if (result < 1) {
perror("error!");
exit(1);
}
if (FD_ISSET(s, &server)) {
//if server can be readable and written do this
client_socket = accept(s, (struct sockaddr*) & clientaddr, &addrlen);
while (buffersize > 0) {
buffersize = recv(client_socket, buf, 1024, 0);
buf[buffersize] = '\0';
printf("%s", buf);
if (buffersize < 1024) {
break;
}
}
buffersize = 1;
}
}
return 0;}
As you know, TCP takes some time to establish a connection. I want to use the "select" function to reduce the setup time of multi-client connections. I think the function "accept" is the process of establishing connection between client and server, but how to use IO multiplexing in this process, please help me.
the use of select() will delay all client connections to the server.
suggest a sequence similar to:
create a thread pool
create a sockaddr_in
sock_t serverSock = socket()
bind()
listen()
while( 1 )
{
sock_t clientSock = accept( serverSock, ... )
pass clientSock to available thread and mark thread as 'busy'
}
That way, the communication with a client does not 'hang' on a select(), nor a accept()
in each thread:
while(1)
{
wait until thread marked as 'busy'
sock_t mySocket = passedSocket
perform all communication with the specific client
close( mySocket );
mark thread as 'idle'
}
I coded a UDP socket client-server in C. The client sent a query to the server each second for a long time (e.g.: 1 week).
My code ran fine, but I can see in the timeline that the ram increased considerably, at around 14 hours the memory increased to 150M approximately.
The increment is in the client side, the server is working fine.
I need to detect what causes this problem because the program will be running for long time.
What's wrong in my code?
This is my code in the client side:
int consultar_servidor(char *t1_str_)
{
struct timeval t_ini, t_fin, tv;
double secs;
char cadena_enviada[67];
char cadena_recibida[67];
char tx_str[51]= "|0000000000000000|0000000000000000|0000000000000000";
int validacion, i;
long long int t4;
char t4_str[20];
char t2_str_rec[20];
char t2_pps_str_rec[20];
char t3_str_rec[20];
int nBytes, numfd;
if (t1_str_ != 0)
{
strcpy(cadena_enviada,t1_str_);
strcat(cadena_enviada,tx_str);
}
else
{
error("Error recepcion t1");
return 1;
}
if (cont_parametros == 0)
{
set_param();
}
if ( connect( clientSocket, ( struct sockaddr * ) &serverAddr, sizeof( serverAddr) ) < 0 )
error( "Error connecting socket" );
if ( sendto(clientSocket,cadena_enviada,sizeof(cadena_enviada),0,(struct sockaddr *)&serverAddr,addr_size) < 0)
{
close(clientSocket);
error( "Error sentto function");
cont_parametros = 0;
return 1;
}
/** Socket nonblock **/
int flags = fcntl(clientSocket, F_GETFL, 0);
fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(clientSocket, &readfds);
numfd = clientSocket + 1;
/** Set 700us to receive **/
tv.tv_sec=0;
tv.tv_usec=700000;
/** Server send me **/
int recibo = select(numfd, &readfds,NULL,NULL,&tv);
switch (recibo)
{
case -1:
/** Error reception **/
error("Error reception");
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros=0;
return 1;
case 0:
/** Timeout and close socket **/
error( "Error timeout" );
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros = 0;
return 1;
default:
/** If socket contain data **/
if (FD_ISSET(clientSocket, &readfds))
{
/** catch t4 **/
t4=ts();
sprintf(t4_str, "%lld", t4);
/** Receive server message**/
nBytes = recvfrom(clientSocket,cadena_recibida,sizeof(cadena_recibida),0,NULL, NULL);
/** If si a bad data **/
if (nBytes < 0)
{
error( "Error recept data" );
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros = 0;
return 1;
}
/** Clean set **/
FD_CLR(clientSocket, &readfds);
int i;
/** trim t2**/
for(i=17;i<33;i++) t2_str_rec[i-17]=cadena_recibida[i];
t2_str_rec[16]= '\0';
/** trim t3**/
for(i=34;i<51;i++) t3_str_rec[i-34]=cadena_recibida[i];
t3_str_rec[16]= '\0';
printf("%s|%s|%s|%s\n",t1_str_, t2_str_rec, t3_str_rec, t4_str);
return 0;
}
}
}
And the function to set the params socket:
void set_param()
{
/** Set client params **/
memset(&local_addr, 0, sizeof(struct sockaddr_in));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(SRC_PORT);
local_addr.sin_addr.s_addr = inet_addr(SRC_IP);
/** Configure settings in address struct **/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(DST_PORT);
serverAddr.sin_addr.s_addr = inet_addr(DST_IP);
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if ( clientSocket < 0 )
{
error( "Error socket no create" );
exit(1);
}
if (bind(clientSocket, (struct sockaddr *)&local_addr, sizeof(local_addr))< 0)
{
close(clientSocket);
error( "Error bind in socket" );
exit(1);
}
/** Socket create OK**/
cont_parametros = 1;
}
The main part
int main( int argc, char* argv[] )
{
long long int t1;
char t1_str[20];
while(1)
{
t1=ts();
sprintf(t1_str, "%lld", t1);
consultar_servidor(t1_str);
sleep(1);
}
}
The main problem is that you call
close(clientSocket);
for all branches of the code except when you successfully read the data with recvfrom and return with code 0 from consultar_servidor(). As a result, the socket is never closed and there is a socket descriptor leak.
There may be other bugs in the code, make sure to test it under valgrind.
I suggest to restructure the code to avoid duplication and help to catch bugs such as these. For example, one option is to move the cleanup code to a separate function. Another option is to use the goto cleanup pattern, unless you're paranoid about not having goto in your code.
I don't see any actual memory allocations in the posted code, so if there is a direct memory leak, it must be caused by a problem somewhere else in the program.
As #kfx mentioned, another possibility is a socket leak; since each socket comes with buffers that use up a certain amount of RAM, that could show up as increased memory usage as well.
An easy way to test to see if your program is leaking sockets would be to add something like this to your program:
static int socketCount = 0;
int debug_socket(int domain, int type, int protocol)
{
int ret = socket(domain, type, protocol);
if (ret >= 0)
{
++socketCount;
printf("After socket() call succeeded, there are now %i sockets in use by this program\n", socketCount);
}
else perror("socket() failed!");
return ret;
}
int debug_close(int sock)
{
int ret = close(sock);
if (ret == 0)
{
--socketCount;
printf("After close() call succeeded, there now %i sockets in use by this program\n", socketCount);
}
else perror("close() failed!");
return ret;
}
... then temporarily replace all the calls to socket() in your program with debug_socket(), and all the calls to close() in your program with debug_close().
Then run your program, and watch its stdout output. If the numbers printed in the debug output are constantly increasing, your program is leaking sockets and you'll need to figure out why/how and fix it. If not, then you have some other problem elsewhere.
I'm new in C sockets programming, and I'm trying to implement client-server non-blocking application, by using select(...).
When I run on debug the server code and try to connect the client, the select(...) returns 1 (as expected) but for some reason, the FD_ISSET doesn't find the file descriptor ID in the descriptors set.
I've already spend several days in debugging and I'm running out of ideas what could be the problem.
Any help would be much appreciated!
void server_listen(int port_number){
tcpsock_t * server, * client;
fd_set master_set, working_set;
int listen_sd;
int max_sd, rc, desc_ready, bytes, result, close_conn;
dplist_node_t * reference;
if (tcp_passive_open(&server,PORT)!=TCP_NO_ERROR) exit(EXIT_FAILURE);
if (tcp_get_sd(server,&listen_sd)!=TCP_NO_ERROR) exit(EXIT_FAILURE);
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
do {
timeout.tv_sec = 30;
timeout.tv_usec = 0;
memcpy(&working_set, &master_set, sizeof(master_set));
printf("Waiting on select()...\n");
rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
if (rc < 0)
{
perror(" select() failed");
break;
}
if (rc == 0)
{
printf(" select() timed out.\n");
}
desc_ready = rc;
for (int i=1; i <= max_sd && desc_ready > 0; ++i)
{
if (FD_ISSET(i, &working_set))
{
desc_ready -= 1;
if (i == listen_sd)
{
printf(" Listening socket is readable\n");
//do something with the new socket
}
}
else
{
printf(" Descriptor %d is readable\n", i);
close_conn = FALSE;
//read data from already existing socket connection
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &working_set)) */
}
while (end_server == FALSE);
}
int tcp_passive_open(tcpsock_t ** sock, int port)
{
int result;
struct sockaddr_in addr;
tcpsock_t * s = (tcpsock_t *) malloc(sizeof(tcpsock_t));
s->cookie = 0;
s->port = -1;
s->ip_addr = NULL;
s->sd = -1;
s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PROTOCOLFAMILY;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
result = bind(s->sd,(struct sockaddr *)&addr,sizeof(addr));
result = listen(s->sd,MAX_PENDING);
s->ip_addr = NULL;
s->port = port;
s->cookie = MAGIC_COOKIE;
*sock = s;
return TCP_NO_ERROR;
}
int tcp_get_sd(tcpsock_t * socket, int * sd)
{
*sd = socket->sd;
return TCP_NO_ERROR;
}
Your for loop starts at 1. If listen_sd comes back as 0, your loop will fail.
So, change:
for (int i=1; i <= max_sd && desc_ready > 0; ++i)
Into:
for (int i=0; i <= max_sd && desc_ready > 0; ++i)
Also, with just one file descriptor, you don't really need the for loop at all.
UPDATE:
Since you've posted your tcp_* functions, I can comment further. Because you did not show what PROTOCOLFAMILY, TYPE, and PROTOCOL are, they are suspect.
Since you're having trouble, check the return values from socket, bind, and listen for any error.
For an example of a simple working client/server application, see my answer here: executing commands via sockets with popen()
I am working on a bluetooth socket for past 10 days. I have to switch between client and server mode. I have written a piece of code. I was able to send the packet fine but when i was working for listening mode I faced two problems.
1.The accept was in block mode so it was not able to go back to send mode.
2. I made the socket non block using FNCTL()
But now issue is coming that is is switching between two modes perfectly but it is not receiving any packet. My code is as follow:-
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>
#define MAXPROFILES 2
int SetTimer(struct timeval *tv, time_t sec)
{
gettimeofday(tv,NULL);
tv->tv_sec+=sec;
return 1;
}
void start_scan()
{
struct sockaddr_l2 addr1 = { 0 };
int s=0,h, status,f,contacted;
int search=1;
char *message = "hello!";
char dest[18] = "01:23:45:67:89:AB";
struct neighbor
{
char peer[19];
} p[h];
unsigned char buf[1024];
inquiry_info *devices = NULL;
int max_rsp, num_rsp;
int dev_id, sock, len, flags,cmp;
int x=0,i;
char addr[19] = { 0 };
char name[248] = { 0 };
dev_id = hci_get_route(NULL);
sock = hci_open_dev( dev_id );
if (dev_id < 0 || sock < 0)
{
perror("opening socket");
exit(1);
}
len = 3;
max_rsp = 255;
flags = IREQ_CACHE_FLUSH;
devices = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
struct timeval tv;
SetTimer(&tv,15);
while(search == 1)
{ //fprintf(stderr,"\t%d \n", time);
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &devices, flags);
fprintf(stderr,"%s (%d) %d\n", "done scanning, found ", j, num_rsp);
if( num_rsp < 0 ) perror("hci_inquiry");
for (i = 0; i < num_rsp; i++)
{
ba2str(&(devices+i)->bdaddr, addr);
fprintf(stderr,"\t%s \n", addr);
cmp= strncmp(addr,"10:2E:AF:EB:33:BD",8);
if(cmp==0)
{
fprintf(stderr,"\t%s \t%d\n", addr,cmp);
for(f=0;f<=h;f++)
{
if(p[f].peer[18]==addr[19])
contacted=1;
}
if(contacted==1)
{
contacted=0;
continue;
}
s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
// set the connection parameters (who to connect to)
addr1.l2_family = AF_BLUETOOTH;
addr1.l2_psm = htobs(0x1001);
strncpy(dest, addr, 18);
str2ba( dest, &addr1.l2_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr1, sizeof(addr1));
// send a message
if( status == 0 )
{
status = write(s, "hello", 10);
h++;
p[h].peer[18]=addr[19];
}
if( status < 0 )
{
perror("uh oh");
}
}
} // for
x++;
if(!(x%2))
flags = IREQ_CACHE_FLUSH;
else
flags = 0x00;
if (CheckTimer(&tv,5)==1)
{ //close(sock);
fprintf(stderr,"listen....\n");
start_listen(s);
}
}
}
int start_listen(int s)
{ struct sockaddr_l2 addr1 = { 0 },rem_addr = { 0 };;
fd_set fds;
int client, bytes_read,sock_flags;
char buf1[1024] = {0};
socklen_t opt = sizeof(rem_addr);
struct timeval tv;
addr1.l2_family = AF_BLUETOOTH;
addr1.l2_bdaddr = *BDADDR_ANY;
addr1.l2_psm = htobs(0x1001);
sock_flags=fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL,sock_flags | O_NONBLOCK);
bind(s, (struct sockaddr *)&addr1, sizeof(addr1));
SetTimer(&tv,15);
// put socket into listening mode
while(!0)
{
listen(s, 1);
//fprintf(stderr,"I am listening....\n");
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
//fprintf(stderr,"I failed....\n");
FD_ZERO(&fds);
FD_SET(s,&fds);
ba2str( &rem_addr.l2_bdaddr, buf1 );
memset(buf1, 0, sizeof(buf1));
// read data from the client
bytes_read = read(client, buf1, sizeof(buf1));
if( bytes_read > 0 ){
printf("received [%s]\n", buf1);
fprintf(stderr, "accepted connection from %s\n", buf1);
}
close(client);
if (CheckTimer(&tv,5)==1)
{fprintf(stderr,"done listening...");
SetTimer(&tv,15);
return 1;
}
}//while of the listening mode
}
int CheckTimer(struct timeval *tv, time_t sec)
{
struct timeval ctv;
gettimeofday(&ctv,NULL);
if((ctv.tv_sec > tv->tv_sec))
{
gettimeofday(tv,NULL);
tv->tv_sec+=sec;
return 1;
}
else return 0;
}
int main(int argc, char **argv)
{start_scan();
}
I was able to solve the issue by entering the following command again in listen mode before binding.
s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
But now the issue is my close(client) is not working. I am not able to close the client and listen to new client. Do anyone know why?
There is no need at all to open the server socket! (Unless your remote device is doing something very odd!!) A socket can be used for send and receive -- regardless of whether it is a client socket or a server socket.
Remove all the code to do the listen+accept etc, and write and read to the original (client) socket.(The one done with: "connect(s,...")
If your remote device really needs the two different connections. The use a new variable to hold the socket handle and don't have the server socket handle overwrite the original client handle.