I have below functions written for a server side socket implementation -
void SetUpServerSocket()
{
/* Setting up Server socket*/
struct sockaddr_in srv_addr;
int yes=1;
/* Open datagram socket */
if((bind_my_socket = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
print_log("Bind socket failed");
return ;
}
bzero((char*) &srv_addr,sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(my_ip);
srv_addr.sin_port = htons(my_port);
if(setsockopt(bind_my_socket,SOL_SOCKET,SO_REUSEPORT,&yes,sizeof(yes))!=0)
{
print_log("Can't set socket options'SO_REUSEPORT'");
return;
}
if(bind(bind_my_socket,(struct sockaddr*) &srv_addr,sizeof(srv_addr)) < 0)
{
print_log("Bind failed");
return ;
}
if (listen (bind_my_socket,1024) < 0)
{
print_log("Cannot listen on socket\n");
return;
}
}
void* AcceptMsgConnFromClient()
{
/*This will accept connection from client*/
struct sockaddr_in client_addr;
int client_addr_len, r;
my_socket=0;
client_addr_len=sizeof(client_addr);
r=accept(bind_my_socket,(struct sockaddr *)&client_addr,&client_addr_len);
my_socket=r;
return NULL;
}
void* ReceiveClientMsg()
{
/* This will accept messages from client */
u_char buf[2000];
struct sockaddr_in client_addr;
int client_addr_len;
int len;
pthread_t thread;
int connfd;
u_char* pCmd[100];
AcceptMsgConnFromClient();
//Working here
/*if(my_socket>0){
if(send(my_socket, "Server Hello", strlen("Server Hello"), 0) < 0)
{
print_log("Send data failed\n");
print_log(strerror(errno));
print_log("\n");
}
}*/
memset(buf,0,2000);
for(;;)
{
len=recvfrom(my_socket,buf,2000,0,(struct sockaddr *)&client_addr,&client_addr_len);
if(len<=0)
{
AcceptMsgConnFromClient();
continue;
}
//my logic to handle buffer
} // ;; for
usleep(1000);
close(bind_my_socket);
return NULL;
}
void SendMsgtoClient()
{
if(send(my_socket, "Server Hello to Client", strlen("Server Hello to Client"), 0) < 0)
{
print_log("Send data to client failed\n");
print_log(strerror(errno));
print_log("\n");
return;
}
}
From main(in different file) I've called 'SetUpServerSocket()' once and 'ReceiveClientMsg()' in a thread(required to keep processing the buffer).
From a different function I'm calling 'SendMsgtoClient()' whenever I want to send something to Client. However, this fails with error as 'Socket operation on non-socket'.
But when I send something on same my_socket from ReceiveClientMsg thread, it works, and not when I do it from another function. I tried and printed value of my_socket in SendMsgtoClient(), it has an integer which is same as what is being assigned from AcceptMsgConnFromClient().
I have declared the socket variables used as-
static int bind_my_socket = 0, my_socket = 0;
Any help would be appreciated, thank you!
You're not printing the correct error message. The first call to print_log() is likely to change errno, so you're printing that error message, not the error from send(). Save errno in another variable.
void SendMsgtoClient()
{
if(send(my_socket, "Server Hello to Client", strlen("Server Hello to Client"), 0) < 0)
{
int saved_errno = errno;
print_log("Send data to client failed\n");
print_log(strerror(saved_errno));
print_log("\n");
return;
}
}
Related
I am pretty new to socket programming and the C language. I want to teleoperate a robot over the internet for that I have to send some values to a robot computer. Here is my code...
x = state.position_val[0];
y = state.position_val[1];
z = state.position_val[2];
Rx = state.gimbal_joints[0]*1000;
Ry= state.gimbal_joints[1]*1000;
Rz = state.gimbal_joints[2]*1000;
double arr[7] = { x, y, z, Rx, Ry, Rz, btonn };
SAFEARRAY* psa = SafeArrayCreateVector(VT_R8, 0, 7);
void* data;
SafeArrayAccessData(psa, &data);
CopyMemory(data, arr, sizeof(arr));
SafeArrayUnaccessData(psa);
return psa;
These are the code snippets under the while loop at each loop this code gets the state value of the robot and creates an array that is further used for teleoperation. I need to send this array over the internet to another computer.
Please help me how to do this?
I have tested this on Windows machine
Go to https://ngrok.com create an account
your robot should run ngrok client use following commands
ngrok authtoken xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ngrok tcp 80
Forwarding tcp://3.tcp.ngrok.io:15842 -> localhost:80
Here ngrok will assign a local PORT to 80 and random port to outside network ie Interner exposed port. You have to add 80 and that port to your firewall rules of robot network device).
Goto https://whatismyipaddress.com/hostname-ip here put 3.tcp.ngrok.io Look IP address box from ngrok console out. You will get your robot's global IP. that you can connect to your robot from anywhere in the world.
Following are the Client and Server examples that you can compile and run.
gcc .\Client.c -o Client
gcc .\Server.c -o Server
Client.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
//Create a Socket for server communication
short SocketCreate(void)
{
short hSocket;
printf("Create the socket\n");
hSocket = socket(AF_INET, SOCK_STREAM, 0);
return hSocket;
}
//try to connect with server
int SocketConnect(int hSocket)
{
int iRetval=-1;
int ServerPort = 15842; // ngroks external tcp port
struct sockaddr_in remote= {0};
remote.sin_addr.s_addr = inet_addr("3.134.xxx.xxx"); //Robot IP
remote.sin_family = AF_INET;
remote.sin_port = htons(ServerPort);
iRetval = connect(hSocket,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
return iRetval;
}
// Send the data to the server and set the timeout of 20 seconds
int SocketSend(int hSocket,char* Rqst,short lenRqst)
{
int shortRetval = -1;
struct timeval tv;
tv.tv_sec = 20; /* 20 Secs Timeout */
tv.tv_usec = 0;
if(setsockopt(hSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&tv,sizeof(tv)) < 0)
{
printf("Time Out\n");
return -1;
}
shortRetval = send(hSocket, Rqst, lenRqst, 0);
return shortRetval;
}
//receive the data from the server
int SocketReceive(int hSocket,char* Rsp,short RvcSize)
{
int shortRetval = -1;
struct timeval tv;
tv.tv_sec = 20; /* 20 Secs Timeout */
tv.tv_usec = 0;
if(setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO,(char *)&tv,sizeof(tv)) < 0)
{
printf("Time Out\n");
return -1;
}
shortRetval = recv(hSocket, Rsp, RvcSize, 0);
printf("Response %s\n",Rsp);
return shortRetval;
}
//main driver program
int main(int argc, char *argv[])
{
int hSocket, read_size;
struct sockaddr_in server;
char SendToServer[100] = {0};
char server_reply[200] = {0};
//Create socket
hSocket = SocketCreate();
if(hSocket == -1)
{
printf("Could not create socket\n");
return 1;
}
printf("Socket is created\n");
//Connect to remote server
if (SocketConnect(hSocket) < 0)
{
perror("connect failed.\n");
return 1;
}
printf("Sucessfully conected with server\n");
printf("Enter the Message: ");
gets(SendToServer);
//Send data to the server
SocketSend(hSocket, SendToServer, strlen(SendToServer));
//Received the data from the server
read_size = SocketReceive(hSocket, server_reply, 200);
printf("Server Response : %s\n\n",server_reply);
close(hSocket);
shutdown(hSocket,0);
shutdown(hSocket,1);
shutdown(hSocket,2);
return 0;
}
Server.c
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
short SocketCreate(void)
{
short hSocket;
printf("Create the socket\n");
hSocket = socket(AF_INET, SOCK_STREAM, 0);
return hSocket;
}
int BindCreatedSocket(int hSocket)
{
int iRetval=-1;
int ClientPort = 80; //Robot local port
struct sockaddr_in remote= {0};
/* Internet address family */
remote.sin_family = AF_INET;
/* Any incoming interface */
remote.sin_addr.s_addr = htonl(INADDR_ANY);
remote.sin_port = htons(ClientPort); /* Local port */
iRetval = bind(hSocket,(struct sockaddr *)&remote,sizeof(remote));
return iRetval;
}
int main(int argc, char *argv[])
{
int socket_desc, sock, clientLen, read_size;
struct sockaddr_in server, client;
char client_message[200]= {0};
char message[100] = {0};
const char *pMessage = "hello aticleworld.com";
//Create socket
socket_desc = SocketCreate();
if (socket_desc == -1)
{
printf("Could not create socket");
return 1;
}
printf("Socket created\n");
//Bind
if( BindCreatedSocket(socket_desc) < 0)
{
//print the error message
perror("bind failed.");
return 1;
}
printf("bind done\n");
//Listen
listen(socket_desc, 3);
//Accept and incoming connection
while(1)
{
printf("Waiting for incoming connections...\n");
clientLen = sizeof(struct sockaddr_in);
//accept connection from an incoming client
sock = accept(socket_desc,(struct sockaddr *)&client,(socklen_t*)&clientLen);
if (sock < 0)
{
perror("accept failed");
return 1;
}
printf("Connection accepted\n");
memset(client_message, '\0', sizeof client_message);
memset(message, '\0', sizeof message);
//Receive a reply from the client
if( recv(sock, client_message, 200, 0) < 0)
{
printf("recv failed");
break;
}
printf("Client reply : %s\n",client_message);
if(strcmp(pMessage,client_message)==0)
{
strcpy(message,"Hi there !");
}
else
{
strcpy(message,"Invalid Message !");
}
// Send some data
if( send(sock, message, strlen(message), 0) < 0)
{
printf("Send failed");
return 1;
}
close(sock);
sleep(1);
}
return 0;
}
You can now send receive data between robot and your computer
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 have read some example and manual about select and accept but I still can't figure out where I did wrong.
I tried to let server communicate with multiple clients. But when I execute server first, then execute client, server will immediately cause segmentation fault( when i == sockfd in server.c). And I tried to print some strings to check which statement cause wrong, it even no print anything after if (i == sockfd). So I really have no idea how to move on, are there any suggestion?
Server.c
char inputBuffer[140] = {};
char message[] = {"Hi,this is server.\n"};
int sockfd = 0,forClientSockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket creation
struct sockaddr_in serverInfo,clientInfo;
socklen_t addrlen = sizeof(clientInfo);
serverInfo.sin_family = PF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(PORT);
bind(sockfd,(struct sockaddr *)&serverInfo,sizeof(serverInfo));
listen(sockfd,5);
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sockfd, &active_fd_set);
int fd_max = sockfd;
while (1)
{
/* Block until input arrives on one or more active sockets. */
//FD_ZERO (&active_fd_set);
//FD_SET (sockfd, &active_fd_set);
read_fd_set = active_fd_set;
if (select (fd_max+1, &read_fd_set, NULL, NULL, NULL) < 0)
{
printf("select fail\n");
}
/* Service all the sockets with input pending. */
for (i = 0; i <= fd_max; ++i)
{
//printf("%d\n",i);
if (FD_ISSET (i, &read_fd_set))
{
//printf("inner :%d %d\n",i,sockfd);
if (i == sockfd)
{
/* Connection request on original socket. */
//printf("A");
int new;
size = sizeof (clientname);
new = accept (sockfd,(struct sockaddr *) &clientname,&size);
if (new < 0)
{
printf("accept fail\n");
}
else
{
printf (
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
if(new > fd_max)
{
fd_max = new;
}
}
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
return 0;
}
int read_from_client (int filedes)
{
char buffer[140];
int nbytes;
nbytes = recv (filedes, buffer, sizeof(buffer),0);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
printf ("Server: got message: `%s'\n", buffer);
return 0;
}
}
client.c
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket connnection
struct sockaddr_in info;
bzero(&info,sizeof(info));
info.sin_family = PF_INET;
//localhost test
info.sin_addr.s_addr = inet_addr(LOCALHOST);
info.sin_port = htons(PORT);
int err;
char *p;
//Send a message to server
err = connect(sockfd,(struct sockaddr *)&info,sizeof(info));
if(err==-1)
printf("Connection error");
while(1)
{
char message[140];
char receiveMessage[140] = {};
fgets(message,140,stdin);
//scanf("%*[^\n]",message);
//printf("%s",message);
/*if(p=strchr(message,'\n')){
*p = 0;
}else{
scanf("%*[^\n]");
scanf("%c");
}
fgets(message,140,stdin);*/
//scanf("%s",message);
send(sockfd,message,sizeof(message),0);
//printf("RCV");
//recv(sockfd,receiveMessage,sizeof(receiveMessage),0);
//printf("%s\n",receiveMessage);
}
thanks !!
I made a small program server client using sockets. I'll will explain what it needs to do and then the bug.
Application has a server witch wait's for clients. It supports max 6 clients at the same time. For each client server launch a thread in DETASH_STATE and then it come back and listen.
A client will submit the context of a file to the server. (i chose to send line by line)
The server will receive the content sent by a client and save it into a file, with a unique name like: __ft_"Any random string".txt
I hope all is clear till now.
The bug:
Well if i launch the client let say 20 times. On server side i don't have 20 files. Sometimes i have 10, sometimes 12,5,7(unpredictable). It writes in a single file the content sent by 3 or 4 or 5 clients ( here i need to have 3-4-5 files). I don't get where is the bug or what i made wrong. If you need additional information please tell me.
This is the server code (a part of it):
/**********ASSING A PROTOCOL TO A SOCKET (BIND)************/
if(bind(sock_dest, (struct sockaddr *)&server,sizeof (server))<0)
{
printf("Bind failed\n");
return 1;
}
/**********************************************************/
/*************** LISTEN FOR CONNECTIONS ********************/
listen(sock_dest,6);
printf("Waiting for connections\n");
/**********************************************************/
/****ACCEPT CONNECTION AND MAKE ATHREAD FOR EVERY CLIENT***/
c = sizeof ( struct sockaddr_in);
pthread_t thread_id;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
while( ( client_socket = accept( sock_dest, ( struct sockaddr *)&client, (socklen_t *) &c)) )
{
printf("Connection accepted.\n");
if(client_socket < 0)
{
printf("Accepting connection failed.\n");
return 1;
}
if(pthread_create( &thread_id, &attr, connection_handler, (void*) &client_socket ) < 0)
{
printf("Couldn't create a thread for the new client.\n");
return 1;
}
else
printf("Handler assigned\n");
}
return 0;
}
void *connection_handler (void *socket_dest)
{
char *dest_file_name;
char buffer[300];
int sock = *( int *) socket_dest;
char *exit_signal="EXIT";
if((dest_file_name=create_random_name())==NULL)
{
printf("Generating a random name failed\n");
return NULL;
}
int i=0;
while(1)
{
while(i<299)
{
recv(sock,buffer+i,1,0);
if(buffer[i]=='\n')
{
i=0; // setting i to 0 because next time when we read a path(string) it need to be stored from 0 pozition in array.
break;
}
++i;
}
if((strcmp(buffer,exit_signal))==0)
{
printf("Exit signal received.\n");
return NULL;
}
if((write_line_in_file(buffer,dest_file_name))==1)
{
printf("Failed to write one of the lines in %s\n",dest_file_name);
}
printf("Linie primita:%s\n",buffer);
bzero(buffer,256); // put all bytes to 0 from buffer
}
return 0;
}
char *create_random_name(void)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
char *file_name;
int i=0;
int key;
struct stat stbuf;
time_t t;
while(1)
{
srand((unsigned) time(&t));
if((file_name = malloc(16 * sizeof ( char )) ) == NULL)
{
printf("Failed to alloc memory space\n");
return NULL;
}
strcpy(file_name,"__ft_");
for(i=5 ; i<11 ; i++)
{
key = rand() % (int)(sizeof(charset)-1);
file_name[i]=charset[key];
}
strcat(file_name,".txt");
file_name[15] = '\0';
if(stat(file_name,&stbuf)==-1)
{
break;
}
}
return file_name;
}
/************* RETURN 0 IF SUCCES AND 1 IF FAILS ***********/
int write_line_in_file(char *line,char *file_name)
{
FILE *file;
if((file=fopen(file_name, "a")) == NULL)
{
printf("Can't open %s.\n");
return 1;
}
fprintf(file,"%s",line);
fclose(file);
return 0;
}
And this is the client code (i don't think here is the problem):
#include <stdio.h>
#include <stdlib.h>
#include<netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
/***************CHECKING THE ARGUMENT*************/
if (argc < 2)
{
printf("Usage: %s hostname\n", argv[0]);
return 1;
}
/*************************************************/
int sock_dest;
struct sockaddr_in server_addr;
char line[300];
/******************CREATE SOCKET*****************/
sock_dest = socket(AF_INET, SOCK_STREAM, 0);
if(sock_dest == -1)
{
printf("Couldn't create socket.\n");
return 1;
}
struct hostent *server;
server = gethostbyname(argv[1]);
if (server == NULL)
{
printf("ERROR, no such host\n");
return 1;
}
/***** SETTING FIELDS OF SERVER SOCKADDR_IN STRUCTURE *****/
bzero((char *) &server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,(char *)&server_addr.sin_addr.s_addr,server->h_length);
server_addr.sin_port = htons ( 31000 );
/**********************************************************/
/*********TRYING TO CONNECT TO THE SERVER******************/
if (connect(sock_dest,(struct sockaddr *) &server_addr,sizeof(server_addr)) < 0)
{
printf("ERROR:(Can't connect to the server. Please check if it's online)\n");
return 1;
}
/***********************************************************/
char path_read[200];
int read_len,n;
FILE *f_read;
char *exit_signal = "\nEXIT\0";
if((f_read=fopen("test.txt","r"))==NULL)
{
printf("Failed to open path.txt.\n");
return 0;
}
while((fgets(path_read,200,f_read))!=NULL)
{
path_read[strlen(path_read)+1]='\n';
n = write(sock_dest,path_read,strlen(path_read));
if(n<0)
error("ERROR writing to socket");
bzero(path_read,200);
}
n=write(sock_dest,exit_signal,strlen(exit_signal));
fclose(f_read);
close(sock_dest);
printf("All lines in the file were sent to the server.\nExiting...\n");
return 0;
}
This is one bug:
(void*) &client_socket
Firstly, no need to cast to void*. Secondly, it looks like client_socket is a local variable, who's address you pass to the thread as context. In the starting thread, you then continue to overwrite its value with the next iteration.
I am trying to write a multi session chat server in C. I host the server from one terminal and telnet to it from other terminals.
Using ubuntu 13.04 on VMWare player.
What happens is this:
I'm incrementing a loop from 3 onward to fdmax, to accept new connections using sd ( the listener) and newsd represents the new socket descriptor.
When I print 'hi' in one window, it prints in ALL windows including the one I typed in. Plus, a lot of random junk keeps appearing.
I want only what I type to appear(how do i get rid of the junk>), and in all the windows except the one I typed it in!
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/select.h>
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*) sa)->sin_addr);
}
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
int main(int argc, char **argv)
{
//ptr used for traversal, serv used for the linked list of struct addinfos , hints for the getaddrinfo function
struct addrinfo *ptr, hints, *serv;
int max_cli, dat, x, i;
struct sockaddr_storage cli_addr;
socklen_t addr_size;
char cli_ip[INET_ADDRSTRLEN];
char inc[256]; //one command line is 80 characters
memset(inc, 0, strlen(inc));
int sd, newsd;
fd_set master;
fd_set read_fds;
char value[256];
FD_ZERO(&master);
FD_ZERO(&read_fds);
//argv[1]-server ip argv[2]-server port argv[3]-maximum client number
int fdmax;
int opt = 1;
/*if(argc!=4)
{
printf("Please re-enter data. Data insufficient\n");
exit(1);
}
if(atoi(argv[2])<1025)
{
printf("Reserved port. Please try again\n");
exit(1);
}*/
max_cli = atoi(argv[3]);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
/* Verify the inputs and generate linked list of possible IPs to use*/
if (sd = getaddrinfo(argv[1], argv[2], &hints, &serv))
{
fprintf(stderr, "Error calling getaddrinfo %s\n", gai_strerror(sd));
exit(1);
}
for (ptr = serv; ptr != NULL ; ptr = ptr->ai_next)
{
void *addr;
if (ptr->ai_family == AF_INET)
{
struct sockaddr_in *ipv4 = (struct sockaddr_in *) ptr->ai_addr;
addr = &(ipv4->sin_addr);
}
inet_ntop(ptr->ai_family, addr, value, sizeof value);
//printf("%s\n",value);
//Form connection with one of the IP addresses
sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (sd < 0)
continue;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
if (bind(sd, ptr->ai_addr, ptr->ai_addrlen) < 0)
{
close(sd);
continue;
}
break; //Indicates one working socket found and bound
} //end for
if (ptr == NULL )
{
fprintf(stderr, "Bind failed\n");
exit(2);
}
freeaddrinfo(serv);
if (listen(sd, 15) == -1)
{
printf("Error occurred while listening\n");
exit(3);
}
/* Socket found, bound and now listening for active connections*/
FD_SET(sd, &master);
fdmax = sd; //Latest active socket descriptor
while (1)
{
read_fds = master; //Copy the master list so that the original list doesn't get damaged
if (select(fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1)
{
perror("Select failed.\n");
exit(4);
}
for (i = 3; i <= fdmax; i++)
{
//printf("i");
//printf("entered for loop\n");
if (FD_ISSET(i,&read_fds)) //new connection->false, existing one->true
{
// printf("Started reading descriptors!\n");
if (i == sd) //primary connection,exists, accept new file descriptor
{ //printf("Read first connection!\n");
addr_size = sizeof cli_addr;
newsd = accept(sd, (struct sockaddr *) &cli_addr, &addr_size);
printf("Accepted new connection socket %d\n", newsd);
FD_SET(newsd, &master);
if (newsd == -1)
{
perror("accept");
}
if (newsd > fdmax)
{
fdmax = newsd;
}
printf("%d %d\n", newsd, fdmax);
continue;
}
else if (i != sd) //existing connection, so accept data
{
if (dat = recv(i, &inc, sizeof inc, 0) <= 0)
{
if (dat == 0)
{
printf(" Socket %d has quit the chatroom", i);
}
if (dat < 0)
{
perror("Error on Receive");
}
// char *s=&inc;
//printf("%d\n %s",dat);
close(i);
FD_CLR(i, &master);
}
//Nothing wrong with the input from client i. Broadcast!
else
{
for (x = 3; x <= fdmax; x++)
{
if (FD_ISSET(x,&master))
{
if (x != sd)
{
//send(x,&inc,sizeof inc,0);
if (send(x, &inc, sizeof inc, 0) < 0)
{
perror("Send");
}
}
}
}
}
}
}
/*else// new connection
{ break;
printf("SERVERBOT: new connection from %s on socket %d\n",inet_ntop(cli_addr.ss_family,get_in_addr((struct sockaddr*)&cli_addr),cli_ip, INET6_ADDRSTRLEN),newsd);
}////change this to 'username' has joined the room*/
}
}
return 0;
}
First of all, when you send received data, you use sizeof operator, which gives you total size of array. You should send just as many bytes as you received, which will often be less. Use return value of recv to know how many bytes were actually received. In general, C arrays do not have dynamic size, you have to keep track of that yourself.
Then about garbage, you probably print buffer contents without terminating '\0' character. So, either add that (make sure there is the 1 byte of extra space in the buffer!) before printing or using other string functions, or use a printing function which accepts maximum size of string in case that terminating nul is missing.
for a start your send must use dat as length not sizeof(inc)