This program, the client through the server for group chat. The main lecture is two points: 1. How to make non-blocking mode. 2.select of rough explanation (impatient can skip, look directly at the back code)
First, look at the basic logic of this program's server design, which is very simple, polling accept and select functions in a while (1) loop. One might ask, accept is not blocked until a client connects. In fact, when your socket socket is set to non-blocking mode, then accept will not block.
1. How do you make a blockage? This involves fcntl functions. Fcntl can change the properties of a file. Look at his prototype: int fcntl (int fd, int cmd); failed return-1 (of course there are many uses for this function, but here's how he implements Non-blocking) three lines of code:
Long val = fcntl (SOCKFD,F_GETFL); Take the attributes of the SOCKFD socket to Val
Val|=o_nonblock; Adding the non-blocking attribute O_nonblock, using or operating
fcntl (sockfd,f_setfl,val); And then put the good attribute Val, and add it to the SOCKFD.
At this time the SOCKFD as a parameter to Accept,accept will not be blocked.
2.select () function: The Select function can listen for multiple file descriptors at the same time, and if one or more of the file descriptors is responsive (read or write), the select returns. Prototype:
int Select (Nfds, Readfds, Writefds, Errfds, timeout)
Fd_set *readfds, *writefds, *errfds; The 2,3,4 parameter is a set of file descriptors, which is useful for socket programming Readfds.
struct Timeval *timeout; Controls how Select () returns, is non-blocking, blocks a certain time return, or directly has a file description have response.
function Arguments:
1.nfs: The largest file descriptor +1, this can not be wrong, if not sure, write an algorithm to find out, the following provided by the code has
2. Readable file descriptor set. What does that mean, that this centralized file descriptor can write data to the server at any time, and that as a server, you should monitor these file descriptors, and if you don't care about readable, fill in null.
3. Writable file descriptor set. There's no need to talk about it. If you don't care, fill in null
4. exception file descriptor set. If you do not care, you can fill in null.
5. Time Control structure body. There are 2 members in this structure. One represents the second, and one represents the millisecond. Two is set to 0 to indicate that the select will return non-blocking.
For this, there are also columns of macros that are available to select: 1.fd_set (), used to alphanumeric the file description to the file descriptor set 2.fd_zero (), empty all descriptors in the file descriptor set 3.fd_isset (), and determine if a file descriptor has Response. Note: After each return of the Select, the file descriptor set is emptied again, and the file description is alphanumeric to the file descriptor set.
The following is the code for the service side:
TCP Server #include "myhead.h" struct client_list {int sock;
struct Client_list *next;
};
struct Client_list *head = NULL;
struct client_list *init_list (struct client_list*head) {head = malloc (sizeof struct));
Head->sock =-1;
Head->next = NULL;
return head;
The//New client is added to the client queue int add_sock (struct client_list*head,int new_sock) {struct client_list *p = head;
struct Client_list *new_node = malloc (sizeof (struct client_list));
New_node->sock = New_sock;
New_node->next = NULL;
while (p->next!=null) {p = p->next;
} p->next = New_node;
return 0;
}//Find the largest file descriptor int Find_max (struct client_list*head) {struct Client_list *p = head->next;
if (P==null) return 0;
int MAX_SD = p->sock;
for (P;p!=null;p=p->next) {if (Max_sd < p->sock) MAX_SD = p->sock;
return MAX_SD;
The//information is forwarded to other clients int write_to_client (struct Client_list*head,char *wbuf,int size) {struct client_list *p=head; for (p=head->next;p!=null;p=p->Next) {write (p->sock,wbuf,size);
return 0; //When a new client is alphanumeric in as a new file description, all client file descriptors in the client list are displayed void Show_client_list (struct client_list*head) {struct Client_list = he
Ad
if (P->next = = NULL) {printf ("is A EMPTY list!\n");
return;
else {puts ("Client_list is:");
For (p =head->next; p!=null;p = p->next) {printf ("%d", p->sock);
printf ("\ n");
}
}
Cancels the node that exited the client.
int Del_node (struct Client_list*head,int sock) {struct Client_list *p = head->next;
struct Client_list *q = head;
while (P!=null) {if (P->sock = = sock) {Q->next = p->next;
Free (p);
p = NULL;
} else {p = p->next;
Q = q->next;
} return 0;
int main (int argc, char const *argv[]) {char rbuf[50]={0};
Char wbuf[50]={0};
int sockfd,size,on=1;
int new_sock;
int max_sd;
struct Client_list *pos; struct Timeval timeout = {0,0};
Set Select as Non-blocking return Fd_set Fdset;
Long Val; Head = Init_list (head);
Initializes the client linked list.
pos = head;
struct sockaddr_in saddr;
struct sockaddr_in caddr;
size = sizeof (struct sockaddr_in);
Bzero (&saddr,size);
saddr.sin_family = af_inet;
Saddr.sin_port = htons (8888);
SADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any);
SOCKFD = socket (af_inet,sock_stream,0); SetSockOpt (on);//Set socket socket to be reused, not set or//set SOCKFD to non-blocking val = fcntl (
SOCKFD,F_GETFL); Val|=o_nonblock;
Fcntl (Sockfd,f_setfl,val);
Bind (SOCKFD, (struct sockaddr*) &saddr,size);
Listen (sockfd,10); while (1) {New_sock = Accept (SOCKFD, (struct sockaddr*) &caddr,&size);//Loop Accept new Connected client if (new_sock!=-1) {P
UTS ("New Node come!\n");
printf ("New_sock =%d\n", new_sock);
Add_sock (Head,new_sock);
Show_client_list (head); } MAX_SD = Find_max (head); From the client queue, find the largest file descriptor Fd_zero (&fdset);
Empty file Description Descriptor pos = head;
Add each socket to the collection if (Pos->next!= NULL)//If the socket list is not empty {for (Pos=head->next;pos!=null;pos=pos->next) {
Fd_set (Pos->sock,&fdset); } select (Max_sd+1,&fdset,null,null,&timeout); Wait for descriptor for (Pos=head->next;pos!=null;pos = pos->next)//check which socket has a response {if (Fd_isset (Pos->sock,&fdset))
Judge Pos->sock This file descriptor points to a client with no data written over {bzero (rbuf,50);
Read (pos->sock,rbuf,50);
printf ("%s\n", rbuf); if (strcmp (Rbuf, "quit") ==0)//If the information sent by the client is quit, cancelnode for this client.
{Del_node (Head,pos->sock); } write_to_client (head,rbuf,50);
Forward the written information to the other clients in the queue.
}} return 0; }
Client code:
Client #include "myhead.h" int main (int argc, char const *argv[]) {int sockfd;
Char rbuf[50]={0};
Char wbuf[50]={0};
Char ipbuf[50]={0};
int port;
int max_sd;
int size,on=1;
int ret;
Fd_set Fdset;
struct sockaddr_in saddr;
size = sizeof (struct sockaddr_in);
saddr.sin_family = af_inet;
Saddr.sin_port = htons (8888);
SADDR.SIN_ADDR.S_ADDR = inet_addr ("192.168.152.128");
SOCKFD = socket (af_inet,sock_stream,0);
SetSockOpt (Sockfd,sol_socket,so_reuseaddr,&on,sizeof (on));
ret = Connect (SOCKFD, (struct sockaddr*) &saddr,size);
if (ret ==0) {printf ("Connect sucess\n");
Inet_ntop (Af_inet, (void*) &saddr.sin_addr.s_addr,ipbuf,50);
Port = Ntohs (Saddr.sin_port);
printf ("ip:%s,port:%d\n", Ipbuf,port);
else if (ret = = 1) {printf ("failed to connect\n");
return-1;
while (1) {Fd_zero (&fdset); Fd_set (Sockfd,&fdset); Putting the descriptor set of the monitoring service end into the collection fd_set (Stdin_fileno,&fdset); Stdin_fileno This file descriptor is used to monitor standard input (keyboard) MAX_SD = Sockfd>stdin_fileno?soCkfd:stdin_fileno; Select (Max_sd+1,&fdset,null,null,null);
The select here is set to block until there is a file descriptor response if (Fd_isset (Sockfd,&fdset))//To determine whether the server has data sent over {bzero (rbuf,50);
Read (sockfd,rbuf,50);
printf ("%s\n", rbuf);
} if (Fd_isset (Stdin_fileno,&fdset))//Judge whether the keyboard has data sent over {bzero (wbuf,50);
scanf ("%s", WBUF); Write (sockfd,wbuf,50);
The data sent from the keyboard to the server if (strcmp (WBUF, "quit") ==0)//If the keyboard comes to the data is quit, then close this client {printf ("quit!\n");
return 0;
}} return 0; }