Network programming learning diary ---- UDP protocol, IO model, blocking IO

Posted by jawa on Wed, 09 Feb 2022 13:44:11 +0100

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;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Topics: udp