sendto() blocked when the buffer was full, how to solve it? - c

I wanna make a chat room for 4 guys in UDP. Here's the code:
<code>
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<unistd.h>
#define PORT 9999
#define SIZE 1024
int c;
int i=0;
int k=0;
char name[4][20];
char ip[4][16];
FILE * txt;
struct sockaddr_in seraddr,cliaddr[3],getcliaddr[3];
void gettxt()
{
txt=fopen("ip.txt","r");
for(k=0;k<4;k++)
{
c=fgetc(txt);
while(c!=' ')
{
name[k][i]=(char)c;
i++;
c=fgetc(txt);
}
name[k][i]='\0';
i=0;
c=fgetc(txt);
while(c<'1'||c>'3')
c=fgetc(txt);
while(c!='\n')
{
ip[k][i]=c;
c=fgetc(txt);
i++;
}
ip[k][i]='\0';
i=0;
}
for(k=0;k<4;k++)
printf("<%s>%s\n",name[k],ip[k]);
}
int compare(struct sockaddr_in whichcli)
{
int w=1;
for(w=1;w<4;w++)
{
if(whichcli.sin_addr.s_addr==cliaddr[w].sin_addr.s_addr)
break;
}
return w;
}
int main()
{
int com;//compare return value (just the "k")
int qq;
int ret;
int ser;
int maxsock;
char bufrecv[SIZE];
char bufsend[SIZE];
socklen_t clilen=sizeof(cliaddr[1]);//the same wa ~~I guess
gettxt();
fd_set readfds;
seraddr.sin_family=AF_INET;
seraddr.sin_addr.s_addr=inet_addr(ip[0]);
seraddr.sin_port=htons(PORT);
for(qq=1;qq<4;qq++)
{
cliaddr[qq].sin_family=AF_INET;
cliaddr[qq].sin_addr.s_addr=inet_addr(ip[qq]);
cliaddr[qq].sin_port=htons(PORT);
}
ser=socket(AF_INET,SOCK_DGRAM,0);
bind(ser,(struct sockaddr*)&seraddr,sizeof(seraddr));
if(STDIN_FILENO>ser)
maxsock=STDIN_FILENO;
else
maxsock=ser;
while(1)
{
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO,&readfds);
FD_SET(ser,&readfds);
ret=select(maxsock+1,&readfds,NULL,NULL,0);
if(ret>0)
{
if(FD_ISSET(STDIN_FILENO,&readfds))
{
fgets(bufsend,SIZE,stdin);
for(qq=1;qq<4;qq++)
sendto(ser,bufsend,SIZE,0,(struct sockaddr*)&cliaddr[qq],clilen);
}
if(FD_ISSET(ser,&readfds))
{
for(qq=1;qq<4;qq++)
{
recvfrom(ser,bufrecv,SIZE,0,(struct sockaddr*)&getcliaddr[qq],&clilen);
com=compare(getcliaddr[qq]);//
printf("<%s>%s\n",name[com],bufrecv);
}
}
}
}
return 0;
}
</code>
The file "ip.txt" is just the name-IP file, shows as follows:
<txt>
I 192.168.1.2
Sun 192.168.1.4
Jerry 192.168.1.5
Peter 192.168.1.6
</txt>
The first contained the information of my own, the following 3 were other guy's.
But when I ran the program with only one guy, first of all, we can chat with each other with nonblocking. After several words, it didn't work well. I ran gcc and I guessed that when the "sendto" buffer was full, it blocked waiting the other "recvfrom" the buf. The program I wrote is for 4 guys, but I just ran it with only one guy, the other two can't recvfrom it(still the buffer in "recvfrom" I guess,am I right?). So the "sendto" buffer was full and blocked.
That is what I think,am I right?
If it's true, and how to solve it? I mean how to clean the "sendto" buffer periodically? Or there is some other way?
Thanks very much ~~;-)

I think the problem is in your logic, when a client sends you message you loop through all the clients and call recvfrom, you should only call recvfrom once for each time select returns.
if(FD_ISSET(ser,&readfds))
{
struct sockaddr_in src_addr;
socklen_t addrlen = sizeof(src_addr);
recvfrom(ser, bufrecv, SIZE, 0, (struct sockaddr*)&src_addr, &addrlen);
com=compare(src_addr);//
printf("<%s>%s\n",name[com],bufrecv);
}
Edit:
It seems that you use getcliaddr in recvfrom as the src_addr which means that each time you receive a message from a client you overwrite the address of another client, this is not a problem for one client but for more than one you could overwrite the first one with the sender's address and you if you call recvfrom again it would block because you think it's waiting for the first client when it's actually waiting for the second one.

You're misunderstanding the meaning of the src_addr parameter to recvfrom(2):
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
src_addr is an OUTPUT from this function, not an input. It should point at an empty struct sockaddr which it will fill in with the source address of the packet that was received. This means that you can't pick a particular client to receive a packet from (and you don't really want to, as you don't know who is going to be typing next). Instead, you just receive a packet, and then figure out who it was from.

Related

C code to get the interface name for the IP address in Linux

How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.

Check whenever server comes online using UDP in C programming in client

i have written a normal udp client server programm in C programming to send data from client to server and recieve an acknowledgment from it for the message been sent..
so my question is that incase if my server is down and my client sends a message to server ..
how can my client sense whether the server is up or down(nt working).
all sugesstions are welcomed .. and didnot find nythin related to sensing a server.. so please help me on this
the code for client is here
#include<netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sqlite3.h>
void enterdb(char *);
int main()
{
int sfd,l;
char *buf=(char*)malloc(100*sizeof(char)),buf1[10]="";//=(char *)malloc(100*sizeof(char));
struct sockaddr_in server,client;
sfd=socket(AF_INET,SOCK_DGRAM,0);
int sender_len=sizeof(server);
struct msghdr msg;
struct iovec iov;
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(1300);
server.sin_addr.s_addr=inet_addr("127.0.0.1");
msg.msg_name = &server;
msg.msg_namelen = sender_len;
msg.msg_iov = &iov;
msg.msg_iovlen = sizeof(buf1);
msg.msg_iov->iov_base = buf1;
msg.msg_iov->iov_len = 9;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
printf("Enter the message:");
gets(buf);
char *test="quit";
if(strcmp(test,buf)==0)
{
printf("now exiting\n");
close(sfd);
exit(0);
return 0;
}
else
{
int s;
s=sendto(sfd,buf,strlen(buf),0,(struct sockaddr *)&server,sizeof(server));
printf("control passed on here and message sent is of %d bytes \n",s);
printf("control passed on here again and message sent is of %d bytes\n ",s);
//sleep(5);
int length = sizeof(server);
printf("%s\n",buf1);
int x = recvmsg(sfd,&msg,MSG_DONTWAIT);
if(x<0)
{
printf("error");
}
/*while( ( x =recvfrom(sfd,buf1,100,0,(struct sockaddr*)&server,&length)))
{
if(x<0)
return 1;
break;
}*/
else {
printf("%s\n",buf1);
char *recv="recieved";
if(strcmp(recv,buf1) != 0 )
{
printf("**** control is in connect ***\n");
enterdb(buf);
}
else
{
memset(buf,0,strlen(buf));
printf("MESSAGE FOR SERVER : you sent me the message has been- %s\n",buf1);
}
}
}
close(sfd);
return 0;
}
The usual way of detecting whether a server is down is by sending it a message and waiting for the answer for a limited time (maybe 30s, maybe 15 min, depending on the application and the network...). In your case, you'd have to setup a time-out in your client, which you would start on sending a message and stop when receiving the acknowledgment. If the time-out is not stopped before it "wakes up", then it triggers an exception or sets a specific variable (these are usual ways of informing the application that the time-out has elapsed without an answer from the server).

client and server communicating

Iam trying to run shell commands on a server and want them to be printed in the client shell..
that means when i type a command in the client shell that command should go to the server and execute inside the server and return the output back to the client
but the only problem iam, facing now is when i run commands like "Date,hostname etc" in the client programme it shows the expected output(Client -> server -> client). but when i run "ls" it shows only the first file in the folder..
as an example if i put five files in a folder it shows only the name of the first file in the folder
CLIENT program
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#define PORT 1300
#define HOST "127.0.0.1"
#define MAXLINE 1024
main() {
register int s,len;
struct sockaddr_in pin;
struct hostent *hp;
char buff[MAXLINE + 1];
if ((hp=gethostbyname(HOST)) == 0) {
perror("gethostbyname");
exit(1);
}
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
pin.sin_addr.s_addr= ((struct in_addr *) (hp->h_addr)) -> s_addr;
pin.sin_port=htons(PORT);
if ((s=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("client:socket");
exit(1);
}
if (connect(s,(struct sockaddr *) &pin,sizeof(pin)) < 0) {
perror("client:connect");
exit(1);
}
char out[20];
strcpy(out,"exit");
while(1){
bzero(buff,MAXLINE+1);
printf("Message> ");
scanf("%s",buff);
if(strcmp(out,buff) == 0){
exit(1);
}
send(s,buff,strlen(buff)+1, 0);
bzero(buff,MAXLINE+1);
read(s,buff,MAXLINE);
printf("Received>");
puts(buff);
}
close(s);
}
here's my SERVER program
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <time.h>
#include<string.h>
#define PORT 1300
#define MAXLINE 4096
#define COMMAND_LEN 20
#define DATA_SIZE 1512
main() {
register int s,ns;
int len;
struct sockaddr_in sin,pin;
char buff[MAXLINE + 1];
time_t ticks;
struct tm * timeinfo;
FILE *pf;
char command[COMMAND_LEN];
char data[DATA_SIZE];
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr= htonl(INADDR_ANY);
sin.sin_port=htons(PORT);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("server: socket");
exit(1);
}
if (bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("server:bind");
exit(1);
}
if (listen(s,5) <0) {
perror("server: listen");
exit(1);
}
for(; ;) {
if ((ns = accept(s, (struct sockaddr *)&pin, &len)) < 0) {
perror("server: accept");
exit(1);
}
while(1){
bzero(buff,MAXLINE+1);
read(ns,buff,MAXLINE);
pf=popen(buff,"r");
if(!pf)
{
fprintf(stderr,"could not open for output. \n");
}
fgets(data,DATA_SIZE,pf);
send(ns,data,strlen(data)+1,0);
//puts(buff);
//send(ns,buff,strlen(buff)+1,0);
}
}
close(ns);
close(s);
}
i tried changing the buffer size but still the problem remains ...
this is how i changed the code segment in server side
bzero(buff,MAXLINE+1);
read(ns,buff,MAXLINE);
pf=popen(buff,"r");
if(!pf)
{
fprintf(stderr,"could not open for output. \n");
}
while(NULL!=fgets(data,DATA_SIZE,pf)){
send(ns,data,strlen(data)+1,0);
}
if(pclose(pf)!=0)
fprintf(stderr,"Error:failed to close command stream \n");
* data ='\0';
//puts(buff);
send(ns,data,1,0);
and in the client side i changed it as
the below code is just under the main method
int idone =0, ibytes;
char *p;
this part is in the client programme as shown
while(! idone)
{
ibytes = read (s,buff,MAXLINE);
for (p=buff;(ibytes--);p++)
{
if(! *p)
{idone=1;break;}
putc(*p,stdout);
}
now when i run the "ls" command it still shows only one file and now after doing the above change now it doesnt even run commands like "date ,hostname ..."
On the client side,
read(s,buff,MAXLINE);
Is not guaranteed to get all the data that the server sent. In fact it can return after returning 1 byte. You're going to have to add a header to your messages on the server side and then make sure you keep doing read until you receive the entire message.
Not to mention doing one fgets() on the server side means you only read one line from popen() and send that. You need to keep doing fgets() till EOF.
Not to mention that you never close pf with a pclose.
So, now in the comments you've tried to address point 2 & point 3. pclose is in the wrong place, but in addition, you still have the problem of point 1. You don't know how much to read on the client before the "results" are complete. So we have to make up a protocol.
So right now your code in the comments will send each line of ls back with a newline and a \0. Lets change that. Lets only send printable text until everything is done, then send a \0.
while ( NULL != fgets(data, DATA_SIZE,pf)) {
send( ns, data, strlen( data), 0) ; // not strlen() +1
}
if ( pclose( pf) != 0 ) { perror("Error") ; } // outside the while loop
* data= '\0' ;
send( ns, data, 1, 0 ) ; // send a null
Now the client can do read() all day long, and until it gets a \0 it knows there's more data. Beware of a few gotchas of course. You have to add \0 to your client side buffer before printing each message. And when you go looking for \0 in the message, you have to make sure you didn't find it passed the end of the number of bytes sent.
The key here is that you have to look at the return value of read() for how many bytes you actually got.
int idone= 0, ibytes ;
char * p;
while ( ! idone )
{
ibytes= read(s,buff,MAXLINE);
for ( p= buff ; ( ibytes -- ) ; p ++ )
{
if ( ! * p ) { idone= 1 ; break ; }
putchar( * p) ;
}
}

Store a clients struct and use it afterwards

I store my clients like this..
int MAXCLIENTS = 4;
int ClientCount = 0;
int FreeSpot[MAXCLIENTS];
typedef struct CLIENTS_FD{
int sock;
struct sockaddr_in cli_adr;
}cliuse;
cliuse MYCLIENTS[4];
do{
NewSFD = accept(ServerFD,(struct sockaddr *) &cli_addr, &clilen);
if (NewSFD < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
DCSERVER = TRUE;
}
break;
}
if(ClientCount < MAXCLIENTS){
for(loop = 0; loop < MAXCLIENTS; loop++){
if(FreeSpot[loop]<0){
Clients[loop].sock = NewSFD;
break;
}
}
ClientCount++;
}
else
{
printf("Maximum Client Reached.\n");
char *sendtoclient = "Server full";
send(NewSFD, sendtoclient, strlen(sendtoclient),0);
close(NewSFD);
break;
}
ip = ntohl(cli_addr.sin_addr.s_addr);
printf(" Connection from %d.%d.%d.%d\n",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
dlogs(ip);
}while(NewSFD != -1);
I know i can store my clients file descriptor but how can i store my clients struct and use it afterwards i want to send message to it?.. say i want to send message to client with ip 192.168.5.10.
thanks.
I think you miss some important point about network programming. Maybe you should read this for more details and infos how to start.
Nevertheless accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) will fill client addres structure which is second parameter (struct sockaddr *addr). You can then easily add this address to your CLIENTS_FD structure.
Clients[loop].sock = NewSFD;
Clients[loop].cli_adr = cli_addr;
assuming that Clients is cliuse (or struct CLIENTS_FD).
Anyway, like mentioned in some comments above you don't need to store this address anywhere. All you need to communicate with your client is its sockfd (which is returned by accept).
What is more there could be some bugs in your code:
int FreeSpot[MAXCLIENTS];
is uninitialized so when you try to check it
if(FreeSpot[loop]<0)
this could lead to wrong behaviour. You could simply write int FreeSpot[MAXCLIENTS] = {0}; You should then somewhere (probably inside if(FreeSpot[loop]<0) statement) add something like this FreeSpot[loop] = 1; to set it properly before next checks.
int MAXCLIENTS = 4;
int FreeSpot[MAXCLIENTS];
Since C99 it is possible to declare tables using something else than constant. This is called VLA (variable length array). Nevertheless in your case I can see no point to use VLA. Try #define MAXCLIENTS 4 instead (as suggested in some comment above).
To write to the clients, after returning from your do-while loop you can simply use something like below:
send(Clients[i].sock, msg, len, flags);
where i is number of your client (range 0-3), again assuming that Clients is cliuse (or struct CLIENTS_FD).

Why i am not able to read multiple strings in the server file?

While working in client-server programming, I have passed 3 strings in client, which will be received by server and it should be printed in there 3 times. (i.e I have used a 'for' loop which will do the read & write operations in client & server side respectively.), but in server only the 1st string is getting printed.
Please explain,
Here is my code
server.c
#include "head.h"
void readstr(int connfd ,char [][20]);
//void writestr(char * ,int);
int main(int c ,char *v[])
{
int sd,connfd,retbind;
struct sockaddr_in serveraddress ,cliaddr;
socklen_t len;
char buf[100] ,databuf[1024][4];
sd =socket( AF_INET ,SOCK_STREAM ,0);
if (sd<0)
{
exit(1);
}
memset(&serveraddress ,0 ,sizeof(serveraddress));
serveraddress.sin_family =AF_INET;
serveraddress.sin_port =htons(MYPORT);
serveraddress.sin_addr.s_addr =htonl(INADDR_ANY);
retbind =bind(sd ,(struct sockaddr*)&serveraddress ,sizeof(serveraddress
));
if(-1 ==retbind)
{
perror("bind fails ");
exit(0);
}
listen(sd ,4);
for(;;)
{
printf("i am waiting for client\n");
len =sizeof(cliaddr);
connfd = accept(sd ,(struct sockaddr*)&cliaddr ,&len);
if(connfd <0)
{
if(errno ==EINTR)
printf("interrupt");
continue;
}
printf("connection from %s\n",inet_ntop(AF_INET ,&cliaddr.sin_addr,buf ,
sizeof(buf)));
readstr(connfd ,databuf);
close(connfd);
printf("\n fini one clieni");
}
return 0;
}
void readstr(int connfd ,char str[3] [20])
{
int pointer=0 ,i=0, n,pos=0;
memset(str ,'\0',sizeof(str));
printf("\n->Connfd : %d\n",connfd);
printf("\n----->String recieved : %s\n",str);
for(i=0;i<3;i++)
{
while((n=read(connfd ,str[i] ,20)) >>0)
{
printf("Looping while\n");
pos =pos +n;
}
str[i][pos] ='\0';
}
for(i=0;i<3;i++)
{
printf("\n%s",str[i]);
}
}
client.c
#include "head.h"
void send1(int ,char*);
int main(int c,char*v[])
{
int sd,i;
int len;
char buf[20][4];
struct sockaddr_in serveraddress;
sd = socket(AF_INET ,SOCK_STREAM ,0);
if (sd<0)
perror("socket");
memset(&serveraddress ,0 ,sizeof(serveraddress));
serveraddress.sin_family =AF_INET;
serveraddress.sin_port =htons(atoi(v[1]));
serveraddress.sin_addr.s_addr =inet_addr(v[2]);
if(connect(sd,(struct sockaddr*)&serveraddress ,sizeof(serveraddress)) <
0)
{
printf("cannot connect to server");
exit(1);
}
for(i=0;i<3;i++)
{
memset(buf ,'\0',sizeof(buf));
printf("\n string");
fgets(buf[i],20,stdin);
len =strlen(buf[i]);
if(buf[i][len] =='\n')
buf[i][len]='\0';
// scanf("%s",buf[i]);
send1(sd ,(char *)buf);
}
shutdown(sd ,SHUT_WR);
}
void send1(int sd ,char *str)
{
int n ,byteswritten =0, wr;
char buf[1024];
strcpy(buf ,str);
n =strlen(buf);
while(byteswritten < n)
{
printf("\nStart writing in client side\n");
wr = write(sd , buf+byteswritten ,(n-byteswritten));
byteswritten+=wr;
}
printf("\n string sent %s" ,buf);
}
In client.c main:
char buf[20][4];
change to:
char buf[4][20];
In server.c readstr:
while((n=read(connfd ,str[i] ,20)) >>0)
change to:
while((n = read(connfd, &str[i][pos], 20)) > 0)
pos needs to be reset to 0 inside the for loop.
Also, the client reads 3 strings of up to 20 chars each from stdin and writes them to the socket.
The server expects 3 strings of exactly 20 chars each.
You should either use some kind of record separator, like \n, in your network protocol, or use fixed length, i.e. pad the input strings to 20 characters.
There may be more errors in your code, I stopped looking after finding these.
It has been over 1 hour on SO and you haven't got an answer.. to what seems like a very simple problem(odd feat). you know why?
because its very painful to go through your code.
document it!
divide it into modules - init_net(), form_pkt(),
send_pkt(), exit(),.. etc
describe your problem properly.
how many client are you running?
what happens after only first strings get printed. does you code stops, loops forever what?
have you looked through a packet capture tool like tcpdump, wireshark, etc
and before I get to the main problem.. I see things like "databuf[1024][4]" being passed to a function readstr() with formal arguments "char str[3] [20]".
couple of advice
run your code through a static tool analyzer to look for basic warnings.
strings are not a great idea to send on network, learn how to define a packet structure with header and data part, etc
also I believe you are looking for a Packet like communication instead of stream based. understand the difference!
I do not know the answer to that question unless you present it properly. this time and every next time.

Resources