Store a clients struct and use it afterwards - c

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).

Related

C UDP Client-Server stuck comunication

for one of my university courses I must realize a simple chat program in C that uses UDP Client-Server, this is the description that the teacher sent us:
You should develop a private chat environment to exchange
text messages between hosts. Message encryption is optional but not required.
The project should be composed by 2 main modules:
Server: receives and stores each message in a sort of chat database.
A very naive database would consist in a User struct,
that contains everything (login credentials, chats, ...).
Each Chat structure contains the actual messages.
Client: provides a very simple interface to select a
receiver for our message and then write the content of the message.
Login is required. If a receiver is not subscribed returns an error.
The project should be tested with at least 3 users :)
I managed to implement the authentication phase but then when trying to implement the message exchange phase I got stuck. When I try to send the linked_list of online users from the Server to the Client the execution freezes and not only that but it gives somewhat of random behavior, sometimes gets stuck on the first try sometimes on the second and so on. I also noticed that when I introduced a separated thread in the Client to handle the inbox of messages the situation got worst getting stuck more often then before. I will add the code of the functions responsible of sending and receiving the online users and also the link to my git repo where if you want you can find the complete code.
This is the code in the Server:
void Send_list(ListHead* head, int sockfd,struct sockaddr_in cliaddr, int size){
int written_bytes;
int len = sizeof(cliaddr);
char username[50];
if(head->size == 1){
return;
}
ListItem* aux = head->first;
for(int i=0;i<size;i++){
memset(username,0,sizeof(username));
UserListItem* uitem = (UserListItem*) aux;
strcpy(username,uitem->user.username);
do{
written_bytes = 0;
written_bytes = sendto(sockfd,(const char *)username,strlen(username),0,(const struct sockaddr*)&cliaddr,len);
}while(written_bytes != strlen(username));
printf("\nusername mandato: %s",username);
printf("\n");
if(aux->next){
aux = aux->next;
}
}
}
And this is the code in the Client:
int recv_list(int sockfd,struct sockaddr_in servaddr, ListHead* head,int size, char username[50]){
char onuser[50];
int len = sizeof(servaddr);
int read_bytes;
int idx = 1;
if(size == 1){
return 1;
}
for(int i=0;i<size;i++){
read_bytes = recvfrom(sockfd,(char *)onuser,sizeof(onuser),0,(struct sockaddr*)&servaddr,&len );
onuser[read_bytes] = '\0';
if(List_find_by_username(head,onuser) == 0 || strcmp(onuser,username)){
UserListItem* uitem = malloc(sizeof(UserListItem));
memset(uitem,0,sizeof(UserListItem));
UList_init(uitem,onuser);
uitem->idx = idx++;
ListItem* result = List_insert(head,head->last,(ListItem*)uitem);
assert(result);
}
memset(onuser,0,sizeof(onuser));
}
UserList_print(head);
return 0;
}
And this is the link to my git repo: https://gitlab.com/antonio_ciprani/so-progetto-20_21
I work in an Ubuntu based system.
I really hope that somebody can help me because this is driving me crazy :(
I also noticed that when I introduced a separated thread in the Client to handle the inbox of messages the situation got worst getting stuck more often then before.
Indeed the use of threads in your program does more harm than good. Especially that in the main loop you pthread_create a new reciving thread, which competes with the main thread for the incoming messages, disrupts the course of recv_list. Better don't use threads for your project - you'll avoid a lot of problems.
Let's first write two helper functions:
void store(thread_args_t *targs, Message *msg)
{ // code taken from your function "reciving"
if (!strcmp(targs->user->username, msg->reciver))
{
Inbox *mitem = malloc(sizeof (Inbox));
strcpy(mitem->msg.sender, msg->sender);
strcpy(mitem->msg.reciver, msg->reciver);
strcpy(mitem->msg.data, msg->data);
ListItem *result =
List_insert(targs->inbox, targs->inbox->last, (ListItem *)mitem);
assert(result);
}
}
char *input(thread_args_t *targs)
{ // wait for user input and store incoming messages
fflush(stdout);
fd_set fds, fdr;
FD_ZERO(&fds);
FD_SET(0, &fds); // add STDIN to the fd set
FD_SET(targs->sockfd, &fds); // add socket to the fd set
for (; ; )
{
if (fdr = fds, select(targs->sockfd+1, &fdr, NULL, NULL, NULL) < 0)
perror("select"), exit(1);
if (FD_ISSET(0, &fdr))
{ // this is the user's input
static char data[256];
if (!fgets(data, sizeof data, stdin)) return NULL; // no more user input
data[strlen(data)-1] = '\0';
return data;
}
// if no user input, then there's a message
Message msg;
socklen_t len = sizeof targs->servaddr;
if (recvfrom(targs->sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)targs->servaddr, &len) < 0)
perror("recvfrom"), exit(1);
store(targs, &msg);
}
}
Now you can replace the main loop body in main with this:
int ret, op;
printf("\nPlease choose an option: ");
printf("\n1.Send a message!");
printf("\n2.Incoming messages!");
printf("\n3.Logout!");
printf("\nYour choice:\t");
char *str = input(&targs);
sscanf(str, "%d", &ret);
printf("\nqua bro?\n");
if (ret == 1)
{
printf("\nqua loz?\n");
int res, read_bytes, size, id;
op = 3;
socklen_t len = sizeof servaddr;
sendto(sockfd, &op, sizeof op, MSG_CONFIRM,
(struct sockaddr *)&servaddr, len);
printf("\nqua shiiis?\n");
// We cannot preclude that a message arrives here,
// therefore we must handle that case.
Message msg;
while ((read_bytes = recvfrom(sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)&servaddr,
&len)) == sizeof msg)
store(&targs, &msg);
if (read_bytes == -1) perror("recvfrom"), exit(1);
size = *(int *)&msg;
printf("\nqua ci siamo?\n");
res = recv_list(sockfd, servaddr, &on_list, size, user.username);
printf("\nqua?\n");
if (res == 0)
{
printf("\nChoose whom you want to send a message to");
printf("\nYour choice:\t");
str = input(&targs);
sscanf(str, "%d", &id);
printf("\nWrite the message you want to send:\n");
str = input(&targs);
Init_msg(&msg, str, id, &on_list, user.username);
int written_bytes = sendto(sockfd, &msg, sizeof msg, MSG_CONFIRM,
(struct sockaddr *)&servaddr, len);
if (written_bytes == -1) perror("sendto"), exit(1);
// With your present server, a message cannot arrive here, but you
// possibly will want to change that, so let's handle it already.
while ((read_bytes = recvfrom(sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)&servaddr,
&len)) == sizeof msg)
store(&targs, &msg);
if (read_bytes == -1) perror("recvfrom"), exit(1);
int sent = *(int *)&msg;
if (sent == 0) printf("\nMessage sent!");
else
if (sent == 1) printf("\nUser is offline :(");
}
else
if (res == 1) printf("\nNo online user :(");
}
else
if (ret == 2) Print_msg(&inbox);
The next thing you possibly want to improve is modifying the server function Forward_message so that it allows for incoming commands from another client while waiting for a message.

C program-server function error

I am trying to learn C and I can't get these apps working. I am creating 2 apps client/server, where the client connects to a server via specified port, and sends a file name (text) to the server. The server then takes the file name, runs it through a word count function and then responds to the client with filename/line/word/character count. I have gotten the client and the server to connect and communicate but my problem is that I can't seem to pass the client input to the wordcount function properly. Also, I'm not sure my function will return properly as I haven't found an appropriate method of returning a crafted string. Any help would be appreciated. Thanks!
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg){
perror(msg);
exit(1);
}
char * wordcount(char *cfile){
int i = 0;
int ccount = 0;
int wcount = 0;
int lcount = 0;
char *fn = malloc(strlen(cfile+7));
sprintf(fn, "/Files/%s", cfile);
FILE *cfilename = fopen (fn, "r");
while ((i = fgetc(cfilename)) != EOF){
if (i == '\n') {
lcount++;
}
if (i == '\t' || i == ' '){
wcount++;
}
ccount++;
}
printf("%c contains %d words, %d characters and %d lines.\n", cfile, wcount, ccount, lcount);
return 0;
}
int main(int argc, char *argv[]){
int sock, newSock, portno, n;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
char buffer[256];
int index = 5;
int lowPortNum = 2500 + (10 * index);
int highPortNum = 2500 + (10 * index) + 9;
/* Check for proper amount of args */
if (argc < 2){
fprintf(stderr, "ERROR: No port specified. Exiting...\n");
printf("NOTE: Port must be between %d & %d.\n",lowPortNum,highPortNum);
exit(1);
}
/* Create socket by using args to form components */
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock < 0){
error("ERROR: Could not create socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("ERROR: Binding failed.");
return 1;
}
/* Start listening on socket */
listen(sock, 5);
puts("Server is waiting for connection...");
clilen = sizeof(cli_addr);
/* Accept connection from incoming client */
newSock = accept(sock, (struct sockaddr *) &cli_addr, &clilen);
if (newSock < 0){
error("ERROR: Accept failed.");
}
/* Read message from the client */
bzero(buffer, 256);
if (read(newSock, buffer, 255) < 0){
error("ERROR: Cannot read from socket.");
}
//debug
printf("client msg read: %s\n",buffer);
/* Send message to the client */
//wordcount(buffer);
if (write(newSock , wordcount(buffer) , 100) < 0){
error("ERROR: Cannot write to socket.");
}
close(newSock);
close(sock);
return 0;
}
Firstly, I think you've made a mistake here:
char *fn = malloc(strlen(cfile+7));
sprintf(fn, "/Files/%s", cfile);
You probably meant this:
char fn[strlen(cfile) + 8];
sprintf(fn, "/Files/%s", cfile);
You might notice that I've rearranged it a little; I think you wanted to add 7 to the return value of strlen, not to the argument of strlen. I've written 8 instead, because the extra 1 is for a '\0' which goes at the end of your string; that's extremely important. When you're crafting strings, always remember to make space for the '\0'.
Additionally, I've changed your malloc to a variable-length array. You really don't need to use dynamic storage duration (e.g. malloc) for this; try to prefer automatic storage duration unless you absolutely need dynamic storage duration.
Especially considering that your code leaks memory (which is the precise reason to avoid it unless you absolutely need it). Perhaps valgrind would be a useful tool in your development environment? Always remember to free any memory you have mallocd.
There's another error here:
FILE *cfilename = fopen (fn, "r");
while ((i = fgetc(cfilename)) != EOF){
Supposing fopen returns NULL (probably to indicate that the file doesn't exist), the calls to fgetc following it are clearly going to fail in disastrous ways. I think you meant something like this:
FILE *cfilename = fopen (fn, "r");
if (cfilename == NULL) {
/* XXX: HANDLE THIS ERROR! We'll get to this later... */
}
while ((i = fgetc(cfilename)) != EOF){
... and similarly, you've forgotten to fclose that file that was fopend. Always remember to fclose files that you have fopend.
... my problem is that I can't seem to pass the client input to the wordcount function properly
Providing the mistakes mentioned earlier are fixed, you should be able to safely pass the message received from your socket to wordcount as you have in your comment, without crashes or resource leaks: wordcount(buffer);...
You can try that if you like, but bear with me for a moment longer because you have other requirements to assess.
I'm not sure my function will return properly as I haven't found an appropriate method of returning a crafted string.
Think about how standard library functions handle this. You've used one of them here: sprintf(fn, "/Files/%s", cfile);. By accepting the destination (fn) for the string as an argument, sprintf allows you to use whichever storage duration you like. Additionally, this allows sprintf to return some other int value (which you can look up in the sprintf manual in your own time)...
If you design your function to write to a destination pointed to by an argument, like sprintf (and others) do, you'll be able to use your function however you like (e.g. automatic or dynamic storage duration?), too. You'll be able to return an int value indicating success or failure (e.g. when the fopen call fails), too.
Consider the following function, which doesn't even need a return value because there are no error modes:
typedef unsigned long long ullong;
void fcount(FILE *f, ullong *char_count, ullong *word_count, ullong *line_count)
{
rewind(f);
*char_count = 0;
*word_count = 0;
*line_count = 0;
for (;;) {
int c = fgetc(f);
switch (c) {
case EOF: return;
case '\n': (*line_count)++;
case '\t':
case ' ': (*word_count)++;
default: (*char_count)++;
}
}
}
Now consider this wrapper of that function, which does require a return value
int count(char *destination, char *filename) {
char fn[strlen(filename) + 8];
sprintf(fn, "/files/%s", filename);
FILE *f = fopen(fn, "r");
if (f == NULL) {
/* Note: This exit code is defined within <stdlib.h> */
return EXIT_FAILURE;
}
ullong char_count, word_count, line_count;
count(f, &char_count, &word_count, &line_count);
fclose(f);
sprintf(destination, "%s contains %llu words, %llu characters and %llu lines.\n", filename, word_count, char_count, line_count);
return EXIT_SUCCESS;
}
Now you can tell if your function fails or succeeds, just like many of the standard library functions! Yay!
char buf[128];
count(buf, file_name);
printf("%s", buf);
You can also access the string you intended to write... Is this all flowing together?

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.

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

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.

client - searching all services using servbyport() function

I need to do simple client program, when I add port number and client will be serch all services for this port. Now is problem with segmentation fault in if statement.
How to return all services? In my program it will be return just one, I think.
my code:
int main (int argc, char *argv[])
{
int sockfd, n,pol, s;
int numer;
char recvline[MAXLINE +1];
char p;
struct sockaddr_in servaddr;
struct servent *sp;
if (argc != 3)
err_sys("Aby uruchomić podaj: klient <Adres IP> <port>");
s = atoi(argv[2]);
if((sp = getservbyport(s,NULL)) == NULL)
{
printf("port (s): %d \n", s);
printf("port (sp): %d \n", sp->s_port); //segmentation fault
err_sys("problem with port");
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
err_sys("Blad utworzenia polaczenia");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = sp->s_port;
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr)<=0)
err_sys_kom("Blad konwersji do adresu IP dla %s", argv[1]);
printf("%s", sp->s_name);
pol = connect(sockfd, (SA*) &servaddr, sizeof(servaddr));
if (pol < 0)
{
err_sys_kom("Blad polaczenie z serwerem");
close(sockfd);
exit(-1);
}
else
str_cli(stdin, sockfd , 1);
exit(0);
}
EDIT (in response to new new problem - see comments below):
You probably need to get a list of protocols and work with those in a loop. The contents of the loop should roughly be:
Call getprotoent
If the result is NULL, exit the loop.
Else, dig out the protocol name from the returned structure.
Use that name as the second argument for getservbyport
Do what you want to with the result
EDIT (in response to new problem):
if((sp = getservbyport(s,NULL)) == NULL)
So your logic is to read sp ONLY IF sp is NULL. Obviously it will segfault.
It should be:
if((sp = getservbyport(s,NULL)) != NULL)
But then you will point out another new problem:
Why is sp NULL?
This could be because (as per the earlier version of my answer), you did an atoi on something which was not an integer. It could be because of any other reason. We can't say because we don't know what input you give.
This following part of the answer was in response to an old problem that the OP asked in the same question, and has since then chosen to edit over it:
First of all: Since you're using getservbyport, you really should read about services, if you haven't already.
Now on to the error:
getservbyport is of type:
struct servent *getservbyport(int port, const char *proto);
You are passing argv[2] which is of type char * instead of an int for port.
I believe the user inputs this as an argument in your program?
If you know that a char * points to a set of characters which look like an integer, like "1024", then you can convert it to an integer with atoi.
Do this instead, on the line with the error, when calling getservbyport, while making sure you've included stdlib.h:
getservbyport(atoi(argv[2]),NULL)
If argv[2] is NOT representable as an integer, you'll get undefined behavior, so maybe, you'll want to check this first.

Resources