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.
Related
I wonder why this code is not working. I mean: When both the server and client are running I can type and type with no result. However, when I kill the client, the server starts outputting everything I previously wrote to the client app.
full server.c: https://pastebin.com/iXSYLZS3
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
int main(void)
{
// some code to initialize connection
printf("connection accepted!\n");
fflush(stdout);
close(0);
dup(sock);
while (1) {
scanf("%s", str);
printf("%s", str);
fflush(stdout);
}
return(0);
}
full client.c: https://pastebin.com/sFmi72ZP
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT 8080
int main(void)
{
// some code to initialize connection
printf("connected!\n");
fflush(stdout);
close(1);
dup(sock);
while (1) {
scanf("%s", str);
printf("%s", str);
fflush(stdout);
}
return(0);
}
It may appear to 'work', but that is just by accident. Closing the underlying descriptor of a FILE* and replacing it with another is bound to confuse the FILE implementation at some point (most likely during that important demo)
The safe way is to use fdopen to create a new FILE* from the given socket and then use fscanf/fprintf if you insist on using that.
fdopen is a posix function, but so is dup so I guess you are on a posix system.
It works. I just had to add newline at the end of the string for pipe to be flushed. Eg. I used:
printf("%s\n", str);
instead of:
printf("%s", str);
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?
I am getting errors while compiling my simple client server program in C:
undefined reference to 'socket'
undefined reference to 'htons'
undefined reference to 'bind'
undefined reference to 'listen'
undefined reference to 'accept'
undefined reference to 'recv'
undefined reference to '_impure_ptr'
My code for the client:
#include <stdio.h> /* perror() */
#include <stdlib.h> /* atoi() */
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> /* read() */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
int main(int argc, char *argv[]){
int clientSocket,remotePort, status=0;
struct hostent *hostPtr=NULL;
struct sockaddr_in serverName={0};
char buffer[256]="";
char *remoteHost=NULL;
if(3!=argc){
fprintf(stderr,"Usage %s <serverHost <serverPort>\n",argv[0]);
exit(1);
}
remoteHost=argv[1];
remotePort=atoi(argv[2]);
clientSocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(-1==clientSocket){
perror("socket()");
exit(1);
}
/*
* need to resolve the remote server name or IP address
*/
hostPtr=gethostbyname(remoteHost);
if(NULL==hostPtr){
hostPtr=gethostbyaddr(remoteHost,strlen(remoteHost),AF_INET);
if(NULL==hostPtr){
perror("Error resolving server address ");
exit(1);
}
}
serverName.sin_family=AF_INET;
serverName.sin_port=htons(remotePort);
(void)memcpy(&serverName.sin_addr,hostPtr->h_addr,hostPtr->h_length);
status=connect(clientSocket,(struct sockaddr*)&serverName,
sizeof(serverName));
if(-1==status){
perror("connect()");
exit(1);
}
/*
*Client application specific code goes here
*
*e.g. receive messages from server, respond, etc.
*/
while(0<(status=read(clientSocket,buffer,sizeof(buffer)-1)))
printf("%d: %s",status,buffer);
if(-1==status)perror("read()");
close(clientSocket);
return 0;
}
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");
}