1, Network programming communication protocol-- UDP protocol.
1. What are the UDP protocol features? The full name of UDP protocol is "User Data Protocol / user data packet protocol". This protocol is based on connectionless communication, so there are no connect() and accept() in the code of UDP protocol.
2. UDP protocol design steps? Detailed reference: UDP protocol design process jpg
client:
#include "head.h" int main(int argc,char *argv[]) // ./Jack 192.168.19.3 50001 { //1. Create UDP protocol socket. int sockfd = socket(AF_INET,SOCK_DGRAM,0); //2. Write directly. struct sockaddr_in srvaddr; socklen_t len = sizeof(srvaddr); bzero(&srvaddr,len); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET,argv[1],&srvaddr.sin_addr); char buf[100]; while(1) { bzero(buf,sizeof(buf)); fgets(buf,sizeof(buf),stdin); sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&srvaddr,len); if(strncmp(buf,"quit",4) == 0) { break; } } //3. Destroy the mailbox close(sockfd); return 0; }
The server:
#include "head.h" int main(int argc,char *argv[]) // ./Rose 50001 { //1. Create UDP protocol socket. int sockfd = socket(AF_INET,SOCK_DGRAM,0); //2. Bind the IP address to the socket. struct sockaddr_in srvaddr; socklen_t len = sizeof(srvaddr); bzero(&srvaddr,len); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(atoi(argv[1])); srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(sockfd,(struct sockaddr *)&srvaddr,len); //3. Keep waiting for the other party to write to me. char buf[100]; struct sockaddr_in cliaddr; bzero(&cliaddr,sizeof(cliaddr)); while(1) { bzero(buf,sizeof(buf)); recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&cliaddr,&len); printf("%s:%s",inet_ntoa(cliaddr.sin_addr),buf); if(strncmp(buf,"quit",4) == 0) { break; } } //4. Destroy the mailbox close(sockfd); return 0; }
2, IO model.
1. What is the IO model?
In network programming, we can read and write sockets, such as connfd, so we can recv(connfd) or send(connfd).
When the process reads the socket, revc (connfd) will block and wait when there is no data on the socket.
If you need to read data from multiple sockets, you can't block the wait, you need to use the IO model
2. What are the IO models?
There are four IO models: blocking IO, non blocking IO, multiplexing, signal driven
3, Non blocking IO model
1. Blocking IO: when multiple sockets send me data, I will first ask whether the data of the first socket has arrived. If so, I will read it and block the data of one socket
Non blocking IO: when multiple sockets send me data, I will first ask whether the data of the first socket has arrived. If so, I will read. If not, I will read the next socket.
2. How to set non blocking
Normally, when we use a function to read data, it is blocked by default. For example: read (fd) accept, recv, recvfrom. In fact, these functions are not the cause of blocking, but the socket / file descriptor blocking in these functions.
1) create a new file descriptor / socket ------ "which is blocked by default
2) Add the non blocking attribute to the socket / file descriptor --------------, and then it is not blocked
3) Then call read (fd) accept () and so on to avoid blocking
3. How to add a non blocking socket / file descriptor? --------fcntl()------man 2 fcntl
usage method:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
Parameters:
fd: socket / file descriptor for which attributes need to be set
cmd: F_GETFL (void) -- represents the following parameter, which need not be filled in
F_SETFL (int) --------- it means that the following parameter needs to be filled in
arg: O_RDONLY, O_WRONLY, O_RDWR
O_NONBLOCK -- non blocking attribute
Return value: Success:
F_GETFL / / returns the file attribute
F_SETFL / / returns 0
Failed:
-1
4. Suppose there is a file descriptor called fd, how to add non blocking attribute to fd?
① get fd original attribute
int state=fcntl (fd,F_GETFL);
② add non blocking attributes to the original attributes
state=state | O_NONBLOCK
③ set state to fd
fcntl(fd,F_SETFL,state);
Non blocking eg:
client
#include "head.h" int main(int argc,char *argv[]) // ./Jack 192.168.19.5 50001 // . / Jack server's IP address and port number { //1. Create TCP protocol socket. int sockfd; sockfd = socket(AF_INET,SOCK_STREAM,0); //2. Call. struct sockaddr_in srvaddr; socklen_t len = sizeof(srvaddr); bzero(&srvaddr,len); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET,argv[1],&srvaddr.sin_addr); int ret = connect(sockfd,(struct sockaddr *)&srvaddr,len); if(ret == -1) { printf("connect error!\n"); } //3. Continuously send data to the server. char buf[100] = {0}; while(1) { bzero(buf,sizeof(buf)); fgets(buf,sizeof(buf),stdin); send(sockfd,buf,strlen(buf),0); if(strncmp(buf,"quit",4) == 0) { break; } } //4. Hang up. close(sockfd); return 0; }
sever
#include "head.h" int main(int argc, char *argv[]) { //1. Create TCP socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); //2. Bind IP address struct sockaddr_in srvaddr; socklen_t len = sizeof(srvaddr); bzero(&srvaddr, len); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(atoi(argv[1])); srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(sockfd, (struct sockaddr *)&srvaddr, len); //3. Set the listening socket. listen(sockfd, 20); //Sockfd - > blocking (listening socket) //4. Add listening to non blocking socket. int state; state = fcntl(sockfd, F_GETFL); state |= O_NONBLOCK; fcntl(sockfd, F_SETFL, state); //Sockfd - > non blocking (listening socket) //5. Wait for connection struct sockaddr_in cliaddr; bzero(&cliaddr, sizeof(cliaddr)); int connfd; char buf[100] = {0}; while (1) { connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len); if (connfd >= 0) { while (1) { bzero(buf, sizeof(buf)); recv(connfd, buf, sizeof(buf), 0); printf("from:%s", buf); if (strncmp(buf, "quit", 4) == 0) { exit(0); } } } } //6. Close the socket. close(connfd); close(sockfd); return 0; }
Using non blocking IO and kernel linked list to realize chat room
sever
#include "head.h" #include "kernel_list.h" struct list_node { int connfd; //Holds the connected socket connected to the server. struct list_head list; //Count the number of people currently connected to the server. }; struct list_node *init_list_head() { struct list_node *head = malloc(sizeof(struct list_node)); INIT_LIST_HEAD(&(head->list)); return head; } void insert_data_to_list(struct list_node *head, int connfd) { struct list_node *new = malloc(sizeof(struct list_node)); new->connfd = connfd; list_add_tail(&(new->list), &(head->list)); return; } int delete_list_node(struct list_node *head, int connfd) { struct list_node *p = NULL; struct list_node *q = NULL; list_for_each_entry_safe(p, q, &(head->list), list) { if (p->connfd == connfd) { list_del(&(p->list)); free(p); return 0; } } return -1; } void client_quest(struct list_node *head) { char buf[100] = {0}; //Traverse the entire linked list struct list_node *p = NULL; list_for_each_entry(p, &(head->list), list) { bzero(buf, sizeof(buf)); if (recv(p->connfd, buf, sizeof(buf), 0) >= 0) { //The narrator spoke for the customer printf("from %dclient:%s", p->connfd, buf); //If the user chooses to exit the chat room if (strncmp(buf, "quit", 4) == 0) { //Let the user finish and delete himself from the linked list delete_list_node(head, p->connfd); return ; } } } return; } void delete_list(struct list_node *head) { struct list_node *p = NULL; struct list_node *q = NULL; list_for_each_entry_safe(p, q, &(head->list), list) { //1. Disconnect the node from the linked list list_del(&(p->list)); //2. Free up space. free(p); } free(head); return; } int main(int argc, char *argv[]) // ./server 50001 { //0. Initial header node. struct list_node *head = NULL; head = init_list_head(); //1. Create a TCP socket. int sockfd = socket(AF_INET, SOCK_STREAM, 0); //2. Bind IP address. struct sockaddr_in srvaddr; socklen_t len = sizeof(srvaddr); bzero(&srvaddr, len); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(atoi(argv[1])); srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(sockfd, (struct sockaddr *)&srvaddr, len); //3. Set the listening socket. listen(sockfd, 5); //4. Set non blocking listening socket int state; state = fcntl(sockfd, F_GETFL); state |= O_NONBLOCK; fcntl(sockfd, F_SETFL, state); //5. Wait for the client to connect without blocking struct sockaddr_in cliaddr; bzero(&cliaddr, sizeof(cliaddr)); int connfd, ret, i; char buf[100]; while (1) { sleep(1); //6. The boss greeted the guests non blocking at the door. connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len); //7. If someone really comes in for dinner, arrange a table in the array. if (connfd > 0) { //8. Set the newcomer to non blocking. state = fcntl(connfd, F_GETFL); state |= O_NONBLOCK; fcntl(connfd, F_SETFL, state); //9. Store this person in the linked list. insert_data_to_list(head, connfd); //10. Print out the IP address of the person newly connected to the server. printf("New users connect in: %s(%d)\n", inet_ntoa(cliaddr.sin_addr), connfd); } //11. If no one comes in for dinner, the boss will start asking if the client linked to the server has anything to say. client_quest(head); } delete_list(head); return 0; }