I am working on a client/server c project in which I have a server and multiple clients sending requests to it. The application uses sockets for communication (AF_UNIX) and the whole connection part is fine (to say, using other methods rather than the select() one makes everything work just fine).
However, I am willing to use select() in order to notify the server of new events on the file descriptors in the set, which are the server socket fd and the single clients ones.
I have cleared the code from the parts which are not relevant to the issue I'm facing and now I only have the following:
The server, that initializes the socket communication and created a thread which has to perform the select() and accept() functions:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <string.h>
#include <utility.h>
void* handConn(void* address){
int fd_cli;
while(1){
printf("HANDLER: in handler\n");
if (select(max_fd+1, &rdset,NULL, NULL,NULL) == -1) {
perror("select");
exit(EXIT_FAILURE);
}
for(int i=0; i<=max_fd; i++){
if(FD_ISSET(i,&rdset) && i==sfd){
printf("new incoming connection to accept\n");
fd_cli=accept(sfd,NULL,NULL);
FD_SET(fd_cli,&rdset);
if(fd_cli>max_fd) max_fd=fd_cli;
}
else if(FD_ISSET(i,&rdset) && i!=sfd){
printf("event on old connection\n");
}
}
FD_ZERO(&rdset);
}
return (void*) NULL;
}
int main(void){
int i, fd_cli, tid;
max_fd=0;
struct sockaddr_un sa;
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,"tmp/sock", sizeof(sa.sun_path));
if((sfd=socket(AF_UNIX,SOCK_STREAM,0))<0){
perror("Server socket");
exit(EXIT_FAILURE);
}
if ( bind(sfd,(struct sockaddr *)&sa, sizeof(sa))<0){
perror("bind");
exit(EXIT_FAILURE);
}
listen(sfd,10); //10 is just for example purpose only
/* Init fd_set */
FD_ZERO(&rdset);
FD_SET(sfd, &rdset);
max_fd=sfd;
/*Handler thread creation */
if( pthread_create(&tid, NULL, handConn, (void*) &sa)<0){
perror("Handler thread creation");
exit(EXIT_FAILURE);
}
pthread_join(tid, NULL);
return 0;
}
The client, which performs the following (I removed the wrote-bytes control from the code because it is not relevant in this case):
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <utility.h>
int main(){
int fd_cli;
struct sockaddr_un sa;
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,"tmp/sock", sizeof(sa.sun_path));
if( (fd_cli = socket(AF_UNIX, SOCK_STREAM, 0))==-1){
perror("Client socket connection");
return -1;
}
while( (connect(fd_cli,(struct sockaddr*)&sa, sizeof(struct sockaddr_un))) == -1 ) {
if ( errno == ENOENT ) { sleep(1); }
else{
perror("Connect");
exit(EXIT_FAILURE);
}
}
printf("connected to server\n");
/*write something to server*/
int retvalue = write(sfd, writePointer, bytesLeft);
if(retvalue=0) /*handle...*/
if(retvalue==-1){
perror("writing");
return -1;
}
close(fd_cli);
return 0;
}
Last, the library in which are defined the variables used in the codes above:
#ifndef utility_h
#define utility_h
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
fd_set reset;
int sfd; //server fd
int max_fd;
The issue I am facing is that by executing even just one client, the select does not see the incoming connection.
What I would expect is the handler to print the following:
new incoming connection to accept
event on old connection
the first before doing the accept and the second when it intercepts the write.
The program, as it is don't print neither of those, so the handler can't even intercept a new incoming connection.
It just does nothing but getting stuck on select().
What might the issue be?
Related
I worked in Linux.
I only want to print the message on receiver when Sanders sends.
but, the receiver continues to output same message.
I exactly want to get message in receiver, only if sender sends message.
This code is my code.
I try to conditional, but it's not easy. help
//Sender
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd;
char message[100];
printf("Enter \"exit\" to stop: \n");
while(1)
{
fd=open("/home/control/work/io_dev",O_RDWR); //open file
if (fd ==-1) {
printf("Device open error");
exit(1);
}
sleep(1);
write(fd,message,sizeof(message));
printf("Sender>>");
fgets(message,sizeof(message),stdin);// input message
write(fd,message, sizeof(message));//write on file
if(strcmp(message,"exit\n")==0)
break;
write(fd,message,sizeof(message));
close(fd); //file close
}
}
//Receiver
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd;
char message[100];
while(1){
sleep(1);
fd=open("/home/control/work/io_dev",O_RDWR|O_CREAT); // open or create file
if (fd == -1) { //when file open error occurs
printf("Device open error");
exit(1);
}
read(fd, message, sizeof(message));//read file
sleep(1);//wait
if(strcmp(message,"exit\n") ==0)//loop off
break;
if(message[0]!='\0'){
printf("Received>> %s",message);//print
}
write(fd,message,sizeof(message));
close(fd);//file close
sleep(3);
}
}
Delete the first "write(fd,message,sizeof(message));" in sender side.
Delete "if(message[0]!='\0')"in receiver side.
the following proposed code, for receiver
cleanly compiles
performs the desired functionality
properly checks for errors
avoids having to continually open/close the I/O device
echos what was actually received rather than the whole receiver buffer, much of which may contain trash
avoids the use of 'magic' numbers in the code
and now, the proposed code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define MAX_MSG_LEN 100
int main( void )
{
int fd;
char message[ MAX_MSG_LEN ];
fd=open("/home/control/work/io_dev",O_RDWR|O_CREAT, 0666 ); // open or create file
if (fd == -1)
{ //when file open error occurs
printf("Device open error");
exit(1);
}
while(1)
{
ssize_t bytesRead = read(fd, message, sizeof(message));//read file
if( bytesRead <0 )
{
// handle error and exit
perror( "read failed" );
close( fd );
break;
}
if( bytesRead == 0 )
{ // sender closed the connection
// clean up and exit
close( fd );
break;
}
message[ bytesRead ] = '\0';
if(strcmp(message,"exit\n") ==0)//loop off
break;
printf("Received>> %s",message);//print
if( write(fd,message,strlen(message)) != strlen( message ) )
{
// handle incomplete message write
}
}
close(fd);//file close
}
HOWEVER, if your trying to 'pace' the read/write operations with multiple readers and writers; then strongly suggest using a mutex to avoid any 'race' conditions and maybe even mkfifo() for creating the file. Remember to (before exiting the program) to destroy the fifo.
If deciding to use a FIFO, then be sure to call unlink( filename ); so the file will be destroyed when the program exits
If you want to keep the repeated open/close in the while() loop, then use O_EXCL rather than O_CREAT so the separate programs cannot step on each other.
I'm trying to setup a client/server in C. I establish the connection, then I want to send an username and a pwd to the server, and the server has to reply confirming that he has received the usr/pwd. The problem is that both server and client exit as soon as they meet the "write" or "read" function. What should I do?
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
void main(){
int ds_sock;
struct sockaddr_in my_addr;
ds_sock=socket(AF_INET,SOCK_STREAM,0);
memset(&my_addr,0,sizeof(my_addr));
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(25000);
my_addr.sin_addr.s_addr=INADDR_ANY;
if(bind(ds_sock,(struct sockaddr *)&my_addr,sizeof(my_addr))<0){
printf("error in bind");
}
listen(ds_sock,2);
int ds_sock_acc;
struct sockaddr_in addr;
size_t sin_size = sizeof(struct sockaddr_in);
signal(SIGCHLD,SIG_IGN);
while(1){
if((ds_sock_acc=accept(ds_sock,(struct sockaddr *)&addr,&sin_size))<1){
printf("error accept");
}
printf("connected");
char usr[10];
read(ds_sock,usr,10);
char* confirm_usr;
confirm_usr="Username received";
write(ds_sock,confirm_usr,100);
char pwd[10];
read(ds_sock,pwd,10);
char* confirm_pwd;
confirm_pwd="Password received";
write(ds_sock,confirm_pwd,100);
}
}
client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
void main(){
int ds_sock;
ds_sock = socket(AF_INET, SOCK_STREAM,0);
int ret;
struct sockaddr_in Eaddr;
Eaddr.sin_family = AF_INET;
Eaddr.sin_port = htons(25000);
Eaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
ret = connect(ds_sock,(struct sockaddr *)&Eaddr,sizeof(Eaddr));
if(ret==-1){
printf("error connect");
exit(EXIT_FAILURE);
}
printf("connect OK");
char usr[10];
printf("Insert username");
scanf("%s",usr);
char pwd[12];
printf("Insert password");
scanf("%s",pwd);
printf("%s",pwd);
write(ds_sock,usr,10);
char usr_reply[100];
read(ds_sock,usr_reply,100);
printf("%s",usr_reply);
write(ds_sock,pwd,12);
char pwd_reply[100];
read(ds_sock,pwd_reply,100);
printf("%s",pwd_reply);
}
While the first answer is pretty complete, I wanted to add the 141 error is a SIGPIPE error. (check this in linux manual)
You can strace your program to find the error code or implement errno and perror.
You're accessing out of bounds, thus triggering undefined behavior in your write() call:
char* confirm_usr;
confirm_usr="Username received";
write(ds_sock,confirm_usr,100);
You're asking write() to send 100 bytes, but you only provide a pointer to 18 bytes. Reading any more than 18 from that location triggers undefined behavior. It would make more sense to use strlen() to avoid hardcoding the length:
const char *confirm_usr = "Username received";
write(ds_sock, confirm_usr, strlen(confirm_usr) + 1);
I made it + 1 to actually send the terminating '\0'-character, otherwise the other end has no way of figuring out when the string ends.
Also, you must check the return value of lots of calls, I/O can and will fail and just must deal with that.
It's also pretty strange that it looks as if both server and client begin by doing a read(), and that the server does I/O on a socket different from ds_sock_acc.
I have a loop that is always true to allow other clients to connect. The problem I am having is how do I constantly check the shared memory to see if it changes to know when it is time to shut down the server? The while loop I put in works but it will not let any other clients to connect after. The issue is that in the while(1) loop, it has to wait for another client to connect before going through the loop but I need it to always be checking the shared memory not just when another client connects.
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
struct sockaddr_in sn;
struct sockaddr from;
int main(int ac, char** other){
int s, ns, sl, x = 22, pid;
char b[256];
key_t key=137;
int size=1;
int shmflg=0;
int id=0,ok=0;
char shmstr[10];
char istr[10];
int *shmptr;
size=size*sizeof(int);
shmflg=IPC_CREAT | SHM_R | SHM_W;
id=shmget(key,size,shmflg);
sprintf(shmstr,"%d",id);
shmptr=shmat(id,0,0);
shmptr[0]=0;
s=socket(AF_INET, SOCK_STREAM,0);
if (s<0) {
printf("server socket error\n");
exit(0);}
else {}
bzero((char *)&sn, sizeof(sn));
sn.sin_family = AF_INET;
sn.sin_port = htons(3311);
if (bind(s,(struct sockaddr *)&sn,sizeof(sn))==-1){
printf("server bind error %d\n",errno);
exit(0);}
else {}
listen(s,3);
////////////////////////////////////****************************************
while (1){
sl=sizeof(from);
ns =accept(s,&from,&sl);
if (ns <0) {
printf("server accept error");
exit(0);}
else {}
sprintf(b,"%d",ns);
if ((pid=fork()) == 0) {
sprintf(istr, "%d",ok);
execlp(other[1], other[1], b, shmstr, istr, (char*) NULL);
}
else {
while(shmptr[0]==0){}//allows the server to shut down but no more clients connect
close(s);
exit(0);
}
}
}
////////////////////////////////////////////*************************
close(s);
return 0;
}
If I understand you correctly, non-blocking socket is what you are looking for.
[edit:]
use select
http://www.scottklement.com/rpg/socktut/nonblocking.html
Non-blocking sockets can also be used in conjunction with the select()
API. In fact, if you reach a point where you actually WANT to wait for
data on a socket that was previously marked as "non-blocking", you
could simulate a blocking recv() just by calling select() first,
followed by recv().
I'm working on a problem wich implies a basic running server client(done one before). the problem is that I run server than I run client. My msg Que is created i nboth client takes my char as input sends it, i get the confirmation print but my server msgrcv isn't responding.
s.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <errno.h>
#include "struc.h"
int main(){
int qt;
struct msg m;
qt = msgget(1271,IPC_CREAT|IPC_EXCL|0600);
if(qt < 0){ perror("Error MSGGET()\n");}
printf("msg queue created!\n");
if(msgrcv(qt,&m,sizeof(struct msg),0,0)<0){
perror("Msg recive error");
}
printf("msg recived!\n");
msgctl(qt,IPC_RMID,NULL);
return 0;
}
c.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <errno.h>
#include "struc.h"
int main(){
int qt;
struct msg m;
qt = msgget(1271,0);
if(qt < 0){ perror("~~~ Error MSGGET()\n");}
printf("msg created!\n");
printf("Enter one char: !\n");
scanf("%c",&m.c);
msgsnd(qt, &m,sizeof(struct msg),0);
printf("msg sent!\n");
return 0;
}
struc.h
struct msg{
long mtype;
// matrix M;
char c;
};
(By creating the 3 files you cna test it yourself. Any idea is welcome maybe i missed something)
You should do this to verify that sending doesn't fail.
if(msgsnd(qt, &m,sizeof(struct msg),0)) < 0) {
perror("Msg send error");
}
You should also heed the docs for msgsnd:
The msgp argument is a pointer to caller-defined structure of the
following general form:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
That is, you have to set the mtype in the message you send to be > 0. Currently it is uninitialized, so you should do:
m.mtype = 1;
if(msgsnd(qt, &m,sizeof(struct msg),0)) < 0) {
perror("Msg send error");
}
I have the following libev code:
#include <ev.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <string.h>
#include <stdlib.h>
#include <sys/un.h>
#include <netinet/in.h>
ev_io stdin_watcher;
static void cb(EV_P_ ev_io *w, int revents){
puts ("hello");
//read file here - suggestion due to Ioan
#define BUF_LEN 10
char buf[BUF_LEN];
memset(buf,0,BUF_LEN);
int byte_read;
while( (byte_read = recv(w->fd,buf,BUF_LEN-1,0)) > 0) {
printf("len: %i: %s",byte_read,buf);
memset(buf,0,BUF_LEN);
}
if(-1 == byte_read && EAGAIN != errno) {
perror("recv");
}
close(w->fd);
//ev_io_stop (EV_A_ w);
//ev_unloop (EV_A_ EVUNLOOP_ALL);
}
int main (void){
struct ev_loop *loop = ev_default_loop (0);
int len;
int sd;
sd=socket(AF_UNIX,SOCK_STREAM,0);
struct sockaddr_un address;
//memset(&address,0,sizeof(address));
address.sun_family=AF_UNIX;
strcpy(address.sun_path,"/tmp/mysocket");
unlink(address.sun_path);
len=strlen(address.sun_path)+sizeof(address.sun_family);
int x=bind(sd,(struct sockaddr*)&address,sizeof(address));
printf("%d\n",x);
listen(sd,5);
ev_io_init(&stdin_watcher,cb,sd,EV_READ);
ev_io_start(loop,&stdin_watcher);
ev_loop (loop, 0);
// unloop was called, so exit
return 0;
}
Everything works just fine (almost). Compile: gcc file.c -lev, and run ./a.out. Then write to the socket that ./a.out is listening on: echo "gobblydeegook" | nc -U /tmp/mysocket.
Hello appears on the console as expected.
But the program calls the event and then it keeps printing "hello" ad-infinitum! I want it to continue monitoring this unix socket for writes. How to do this?
The event gets called when there is data to be read on the socket. Since you aren't removing the data from the socket, just printing "hello", the event is called again for you to handle the data.