Network programming -- implementation of server and client

Posted by gnunoob on Fri, 18 Feb 2022 06:53:24 +0100

This paper continues to study network programming (I)

1, Development steps of Socket server and client

  1. Create Socket
  2. Add information (IP address and port number) to the socket
  3. Monitor network connections
  4. Listen for client access and accept a connection
  5. Data interaction
  6. Close socket

2, Main API s of network programming

1. Specify to speak "Chinese" (connection protocol) - create socket

int socket (int domain,int type,int protocol) ;

Parameter interpretation:
domain: indicates the protocol family used, usually AF_INET stands for internet protocol family (TCP/IP protocol family);

  • AF_INET -- IPv4 Internet domain
  • AF_INET6 - IPv6 Internet domain
  • AF_UNIX - Unix domain
  • AF_ROUTE -- route socket
  • AF_KEY -- key socket
  • AF_UNSPEC - unspecified

Type: Specifies the type of socket:

  • SOCK_STREAM: streaming socket provides reliable and connection oriented communication flow; It uses TCP protocol to ensure the correctness and sequence of data transmission.
  • SOCK_DGRAM: datagram socket defines a connectionless service. Data is transmitted through independent messages, which is disordered, and is not guaranteed to be reliable and error free. It uses the datagram protocol UDP.
  • SOCK_RAW: allows programs to use low-level protocols. Raw sockets allow direct access to underlying protocols such as IP or ICMP. They are powerful but inconvenient to use. They are mainly used for the development of some protocols.

protocol: normally assigned "0".

  • 0 select the default protocol corresponding to the type
  • IPPROTO_TCP - TCP transmission protocol
  • IPPROTO_UDP -- UDP transport protocol
  • IPPROTO_STCP - STCP transmission protocol
  • IPPROTO_TIPC - TIPC transmission protocol

2. Address ready - bind IP address and port number

 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Parameter interpretation:
sockfd: is a socket descriptor;

addr: a pointer to the sockaddr type containing the local IP address, port number and other information. It points to the protocol address structure to be bound to sockfd. This address structure varies according to the address protocol family when creating the socket.
ipv4 corresponds to:

struct sockaddr_in {
		sa_family_t    sin_ family;  //protocol family
		in_port_t      sin_ port;    //Port number
		struct in_addr sin_ addr;    //IP address structure
		unsigned char  sin_ zero[8]; //Padding has no practical significance, just to align with the sockaddl structure in memory, so that the two can convert to each other
};

addrlen: the size of the second parameter

3. Monitoring (only for server)

 int listen(int sockfd, int backlog);

Parameter interpretation:
sockfd: is the server-side socket descriptor returned by the socket system call.

backlog: the number of listeners.

4. Connection

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Return value: the return value of this function is a new socket descriptor. The return value represents the connected socket descriptor, and the first parameter is the server listening socket descriptor. A server usually only creates a listening socket, which exists throughout the life cycle of the server. The kernel creates a connected socket for each client connection accepted by the server process (indicating that the TCP three handshakes have been completed. When the server completes the service to a given client, the corresponding connected socket will be closed.

Parameter interpretation:
sockfd: is the server-side socket descriptor returned by the socket system call.

addr: used to return the protocol address of the connected peer (client)

addrlen: client address length

5. Data sending and receiving

1. The first set of API is commonly used for data sending and receiving

ssize_ t write(int fd, const void*buf,size_ t nbytes);


ssize_ t read(int fd,void *buf,size_ t nbyte);

Parameter explanation: for details, please click to view: Document (I)

2. The second set of API is commonly used for data sending and receiving

  1. Send data on TCP socket function: connected
ssize_ t send(int s,const void *msg,size. t len,int flags);

Parameter interpretation:
s: Is the socket descriptor for which the connection has been established, that is, the return value of the accept function;

msg: point to the buffer where the data to be sent is stored;

len: refers to the length of the data to be sent, and the parameter flags is the control option, which is generally set to 0.

  1. Function to accept data on TCP socket: connected
ssize_ t recv(int s,void *buf,size_ t len,int flags);

Parameter interpretation:
s: The specified socket descriptor (must be a connection oriented socket);

BUF: data and save it to the buffer specified by the parameter buf;

len: length of buffer;

flags: control option, generally set to 0.

6. Connect the client to the host

int connect(int sockfd, const struct sockaddr *addr, socklen_ _t addrlen);

sockfd: is the sockect descriptor of the destination server;

addr: is the address structure pointer of the server's IP address and port number;

addrlen: the address length is often set to sizeof(struct sockaddr).

3, Code implementation of server and customer service

1. Server code

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>


int main(int argc, char **argv)
{
	int s_fd;
	int c_fd;
	int n_read;
	char readBuf[128];
	char msg[128] = {0};
	
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	memset(&s_addr, 0, sizeof(struct sockaddr_in));	//Data initialization 
	memset(&c_addr, 0, sizeof(struct sockaddr_in));	//Data initialization
	
	if(argc != 3){
		printf("Parameter input error\n");
		exit(-1);
	}
	
	//1.socket
	s_fd = socket(AF_INET,SOCK_STREAM, 0);	//Create socket 
	if(s_fd == -1){
		perror("socket");
		exit(-1);
	}
	
	s_addr.sin_family = AF_INET;	//agreement 
	s_addr.sin_port = htons(atoi(argv[2]));	//Port number 
	inet_aton(argv[1], &s_addr.sin_addr);	//IP address 
	//2.bind
	bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));	//binding 
	
	//3.listen
	listen(s_fd, 10);	//Listen for 10 connections 
	
	//4.accept
	int clen = sizeof(struct sockaddr_in);
	
	while(1){
		c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen);	
		if(c_fd == -1){
			perror("accept");
		}
		
		
		printf("Get connection:%s",inet_ntoa(c_addr.sin_addr));
		
		if(fork() == 0){
			
			if(fork() == 0){
				while(1){
					memset(msg, 0, sizeof(msg));
					printf("Please enter a message\n");
					gets(msg);
					//5.write
					write(c_fd, msg, strlen(msg));
				}
			}
		
			//6.read
			while(1){
				memset(readBuf, 0, sizeof(readBuf));
				n_read = read(c_fd, readBuf, 128);
				if(n_read == -1){
					perror("read");	
				}else{
					printf("Get message:%d, %s\n",n_read,readBuf);
				}
			} 
			break;
		}	
	}
	
	return 0;
}

2. Client code

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
	int c_fd;
	int n_read;
	char readBuf[128];
	char msg[128] = {0};
	
	struct sockaddr_in c_addr;
	memset(&c_addr, 0, sizeof(struct sockaddr_in));	//Data initialization
	
	if(argc != 3){
		printf("Parameter input error\n");
		exit(-1);
	}
	
	
	//1.socket
	c_fd = socket(AF_INET,SOCK_STREAM, 0);	//Create socket 
	if(c_fd == -1){
		perror("socket");
		exit(-1);
	}
	
	c_addr.sin_family = AF_INET;	//agreement 
	c_addr.sin_port = htons(atoi(argv[2]));	//Port number 
	inet_aton(argv[1], &c_addr.sin_addr);	//IP address 
	//2.connect
	if(connect(c_fd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(-1);
	}
	
	while(1){
		if(fork() == 0){
			while(1){
				memset(msg, 0, sizeof(msg));
				printf("Please enter a message\n");
				gets(msg);
				//3.write
				write(c_fd, msg, strlen(msg));
			}
		}
		
		while(1){
			memset(readBuf, 0, sizeof(readBuf));
			//4.read
			n_read = read(c_fd, readBuf, 128);
			if(n_read == -1){
				perror("read");	
			}else{
				printf("Messages obtained from the server:%d, %s\n",n_read,readBuf);
			}
		}
	}

		
	return 0;
}

3. Operation results

Topics: network