TCP programming details

1.1 TCP introduction and programming process

TCP review:
​ 1. Connection-oriented streaming protocol, reliable, error-retransmitted, and a corresponding confirmation is given every time a piece of data is received;
​ 2. A link needs to be established before communication;
​ 3. The server is a passive link, and the client is an active link

Differences between TCP and UDP:

TCP C/S Architecture

TCP programming flow

server:
​ Create socket socket()
​ Bind the socket to the server network information structure bind()
​ Set the socket to the listening state listen()
​ Block waiting for the client's connection request accept() (blocking function)
​ Communicate recv()/send()
​ Close the socket close()

Client:
​ Create socket socket()
​ Send client connection request connect()
​ Communicate send()/recv()
​ Close the socket close()

1.2 TCP programming - socket
#include <sys/types>
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
Function: Create a socket and return a file descriptor
 parameter:
	domain:	communication domain, protocol family
			AF_UNIX		local communication
			AF_INET		ipv4 Network protocol
			AF_INET6	ipv6 Network protocol
			AF_PACKET	low-level interface
	type:	type of socket
			SOCK_STREAM		Streaming sockets ( tcp)
			SOCK_DGRAM		datagram socket(udp)
			SOCK_RAW		raw socket
	protocol:	Additional protocol, set to 0 if not required
 return value:
	success:	file descriptor
	fail:	-1

Case:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>

int main(int argc, char **argv){
	//Create a TCP socket with the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("fail to socket");
		exit(1);
	}
	return 0;
}
1.3 connect,send,recv
1.3.1 connect function
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr* addr, socklen_t len);
Function:	Send a client connection request to the server
 parameter:	
	 sockfd:	file descriptor, socket the return value of the function
	 addr:		The network information structure of the server to connect to(Need to set by yourself)
	 addrlen:	addr length
 return value:
	 success: 0
	 fail:-1

Notice:
​ 1.connect will not generate a new socket after establishing a connection
​ 2. After the connection is successful, you can start to transmit TCP data
​ 3. Header file: #include<sys/socket.h>

1.3.2 send function
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd,const void *buf,size_t len,int flags);
Function:		send data
 parameter:	
	sockfd:	file descriptor
			Client: socket the return value of the function
			server: accept the return value of the function
	buf:	data sent
	len:	buf length
	flags:	flag bit
			0	block
			MSG_DONTWAIT	non-blocking
 return value:
	success: number of bytes sent
	fail:-1

Notice:
​ Cannot send 0-length packets with TCP protocol

1.3.3 recv function
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
Function:		Receive data
 parameter:	
	sockfd:	file descriptor
			Client: socket the return value of the function
			server: accept the return value of the function
	buf:	data sent
	len:	buf length
	flags:	flag bit
			0	block
			MSG_DONTWAIT	non-blocking
 return value:
	success: number of bytes received
	fail:-1
	If the sender closes the file descriptor or closes the process, then recv The function will return 0
1.3.4 Client Code

Use the network debugging assistant under windows as a server

Client code:

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

int main(int argc, char **argv){

	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("fail to socket");
		exit(1);
	}
	
	//Step 2: Send a client connection request
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(agrv[2]));
	
	if(connect(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		perror("fail to connect");
		exit(1);
	}
	
	//Step 3: Communicate
	//send data
	char buf[128] = "";
	fgets(buf,128,stdin);
	buf[strlen(buf) - 1] = '\0';
	if(send(sockfd,buf,128,0) == -1){
		perror("fail to send");
		exit(1);
	}
	//Receive data
	char text[128] = "";
    if(recv(sockfd,text,128,0) == -1){
    	perror("fail to recv");
    	exit(1);
    }
    
    printf("from server: %s\n",text);
    
    //Step 4: Close the socket file descriptor
    close(sockfd);
	
	return 0;
}
1.4 TCP server - bind, listen, accept
1.4.1 Requirements for being a TCP server

1. Have a identifiable address;
2. Let the operating system know that it is a server, not a client;
3. Wait for the connection to arrive

For the connection-oriented TCP protocol, the establishment of a connection really means the beginning of data communication.

1.4.2 bind function
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
Function: Bind the socket to the network information structure
 parameter:
	sockfd: file descriptor, socket The return value
	addr:	network information structure  //#include <netinet/in.h>
	addrlen:addrlen length
 return value:
	success: 0
	fail: -1
1.4.3 listen function
#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);
Function:
	Change the socket from active to passive
	Causes the operating system to set up a connection queue for the socket to record all connections to the socket
 parameter:
	sockfd:	socket listen socket
	backlog:length of the connection queue
 return value:
	success: return 0
	fail: other
1.4.4 accept function
#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
Function:
	Take an established connection from the connected queue, and if no connection is available, go to sleep waiting (blocking)
parameter:
	sockfd:	socket listen socket
	cliaddr:Used to store the client socket address structure
	addrlen:address of the length of the socket address structure
 return value:
	success: new file descriptor(As long as the client is connected, a new file descriptor will be generated, and this new file descriptor is dedicated to communicating with the specified client.)
	fail:-1
	
Note: The returned socket is a connected socket, which represents the current connection
1.4.5 TCP server example
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char **argv)
{
	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("fail to socket");
		exit(1);
	}
	
	//Step 2: Bind the socket to the server network information structure
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		perror("fail to bind");
		exit(1);
	}
	
	//Step 3: Set the socket to passive listening state
	if(listern(sockfd,10) == -1){
		perror("fail to listen");
		exit(1);
	}
	
	//Step 4: Block waiting for client connection requests
	int acceptfd;
	struct sockaddr_in clientaddr;
	if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1){
		perror("fail to accept");
		exit(1);
	}
	//Print connected client information
	printf("ip:%s ,port: %d\n",inet_ntoa(clientaddr),ntohs(clientaddr.sin_port));
	
	//Step 5: Communicate
	char buf[128] = "";
	if(recv(acceptfd,buf,128,0) == -1){
		perror("fail to recv");
		exit(1);
	}
	
	printf("from client: %s\n",buf);
	
	strcat(buf,"*_*");
	if(send(acceptfd,buf,128,0) == -1){
		perror("fail to send");
		exit(1);
	}
	
	return 0;
}
1.5 TCP programming - close, three handshake, four wave
1.5.1 close closes the socket

1. Use the close function to close the socket (closing a socket representing a connected socket will cause the other end to receive a 0-length packet)

2. When working as a server
​ 1> Closing the listening socket will cause the server to fail to receive new connections, but will not affect already established connections
​ 2> Closing the connected socket returned by accept will cause the connection it represents to be closed, but it will not affect the server's listening

3. When working as a client

​ Closing the connection is closing the connection, it does not mean other

1.5.2 Three-way handshake
1.5.3 Four waves
1.6 TCP concurrent server

TCP is not originally a concurrent server, and a TCP server can only communicate with one client at a time.

Original code:

client.c

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

int main(int argc, char **argv){

	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("fail to socket");
		exit(1);
	}
	
	//Step 2: Send a client connection request
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(agrv[2]));
	
	if(connect(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		perror("fail to connect");
		exit(1);
	}
	
	//Step 3: Communicate
	//send data
	char buf[128] = "";
	while(1){
		fgets(buf,128,stdin);
		buf[strlen(buf) - 1] = '\0';
		if(send(sockfd,buf,128,0) == -1){
			perror("fail to send");
			exit(1);
		}
		if(strncmp(buf,"quit",4) == 0){
			exit(0);
		}
		
		//Receive data
		char text[128] = "";
    	if(recv(sockfd,text,128,0) == -1){
    		perror("fail to recv");
    		exit(1);
    	}
    
  	  printf("from server: %s\n",text);
    }
   	//Step 4: Close the socket file descriptor
   	close(sockfd);
	
	return 0;
}

server.c

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

int main(int argc, char **argv)
{
	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("fail to socket");
		exit(1);
	}
	
	//Set the socket to allow reuse of native addresses or set to port multiplexing
	int on = 1;
	if(setsockopt(sockfd,SOL_SOCKET,SO)REUSEADDR,&on,sizeof(on) < 0){
		perror("fail to setsockopt");
		exit(1);
	}
	
	//Step 2: Bind the socket to the server network information structure
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		perror("fail to bind");
		exit(1);
	}
	
	//Step 3: Set the socket to passive listening state
	if(listern(sockfd,10) == -1){
		perror("fail to listen");
		exit(1);
	}
	
	//Step 4: Block waiting for client connection requests
	int acceptfd;
	struct sockaddr_in clientaddr;
	if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1){
		perror("fail to accept");
		exit(1);
	}
	//Print connected client information
	printf("ip:%s ,port: %d\n",inet_ntoa(clientaddr),ntohs(clientaddr.sin_port));
	
	//Step 5: Communicate
	char buf[128] = "";
	ssize_t bytes;
	while(1){
		if(bytes = recv(acceptfd,buf,128,0) < 0){
			perror("fail to recv");
			exit(1);
		}
		else if(bytes == 0){
			printf("the clinet quited\n");
			exiy(1);
		}
		
		if(strncmp(buf,"quit",4) == 0){
			exit(0);
		}
	
		printf("from client: %s\n",buf);
	
		strcat(buf,"*_*");
		if(send(acceptfd,buf,128,0) == -1){
			perror("fail to send");
			exit(1);
		}
	}
	return 0;
}

Reasons why TCP cannot achieve concurrency:
Since there are two read blocking functions on the TCP server side, accept and recv, the two functions need to be run one after the other, so when one function is running, the other function cannot be executed, so it is impossible to ensure that the client is connected while communicating with other clients.

How to implement a TCP concurrent server:
1. Use multiple processes to implement a TCP concurrent server
2. Use multiple threads to implement a TCP concurrent server

1.6.1 Multi-process to achieve concurrency
int sockfd = socket();
bind()
listen()
while(1)
{
	accept()
	pid = fork();
	if(pid > 0)
	{
	
	}
	else if(pid == 0)
	{
		while(1)
		{
			recv()/send()
		}
	}
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>

//Implementing a TCP concurrent server using multiple processes

#define N 128
#define ERR_LOG(errmsg)do{\										perror(errmsg);\
						exit(1);\
						}while(0)
						
void handler(int sig){
	wait(NULL);
}

int main(int argc, char **argv)
{
	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		ERR_LOG("fail to socket");
	}
	
	//Set the socket to allow reuse of native addresses or set to port multiplexing
	int on = 1;
	if(setsockopt(sockfd,SOL_SOCKET,SO)REUSEADDR,&on,sizeof(on) < 0){
		ERR_LOG("fail to setsockopt");
	}
	
	//Step 2: Bind the socket to the server network information structure
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		ERR_LOG("fail to bind");
	}
	
	//Step 3: Set the socket to passive listening state
	if(listern(sockfd,10) == -1){
		perror("fail to listen");
		exit(1);
	}
	
	//Use signals to handle zombie processes asynchronously
	signal(SIGCHID,handler)
	
	while(1){
		//Step 4: Block waiting for client connection requests
		int acceptfd;
		struct sockaddr_in clientaddr;
		if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1){
			perror("fail to accept");
			exit(1);
		}
		//Print connected client information
		printf("ip:%s ,port: %d\n",inet_ntoa(clientaddr),ntohs(clientaddr.sin_port));
	
		//Step 5: Use the fork function to create a child process, the parent process continues to be responsible for the connection, and the child process is responsible for communicating with the client
		pid_t pid;
		if((pid = fork()) < 0){
			ERR_LOG("fail to fork");
		}
		else if(pid > 0){
			//The parent process is responsible for executing accept, so after the if statement ends, it continues to block at the position of the accept function
		}
		else{
			//The child process is responsible for communicating with the specified client
			char buf[128] = "";
			ssize_t bytes;
			while(1){
				if(bytes = recv(acceptfd,buf,128,0) < 0){
					perror("fail to recv");
					exit(1);
				}
				else if(bytes == 0){
					printf("the clinet quited\n");
					exit(1);
				}
		
				if(strncmp(buf,"quit",4) == 0){
					exit(0);
				}
	
				printf("from client: %s\n",buf);
	
				strcat(buf,"*_*");
				if(send(acceptfd,buf,128,0) == -1){
					perror("fail to send");
					exit(1);
				}
			}
		}
	}
	return 0;
}
1.6.2 Multi-threaded concurrent implementation
void *thread_fun(void *arg){
	while(1){
		recv()/send()
	}
}

sockfd = socket()
bind()
listen()
while(1)
{
	accept()
	//As long as there is a client connection, create a child thread to communicate with it
	pthread_create(&thread,NULL,thread_fun,...)
	pthread_detach();	
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>

//Implementing a TCP concurrent server using multiple processes

#define N 128
#define ERR_LOG(errmsg)do{\										perror(errmsg);\
						exit(1);\
						}while(0)
						
typedef struct{
	struct sockaddr_in addr;
	int acceptfd;
}MSG;

void *pthread_fun(void *arg){
	char buf[N] = "";
	ssize_t bytes;
	MSG msg = *(MSG *)arg;
	while(1){
		if(bytes = recv(msg.acceptfd,buf,128,0) < 0){
			perror("fail to recv");
			exit(1);
		}
		else if(bytes == 0){
			printf("the clinet quited\n");
			exit(1);
		}
		
		if(strncmp(buf,"quit",4) == 0){
			printf("The client quited\n");
			pthread_exit(NULL);
		}
		printf("[%s - %d]: %s\n",inet_ntoa(msg.addr.sin_addr),ntohs(msg.addr.sin_port),buf);
		strcat(buf,"*_*");
		if(send(msg.acceptfd,buf,128,0) == -1){
			perror("fail to send");
			exit(1);
		}
	}
}

int main(int argc, char **argv)
{
	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		ERR_LOG("fail to socket");
	}
	
	//Set the socket to allow reuse of native addresses or set to port multiplexing
	int on = 1;
	if(setsockopt(sockfd,SOL_SOCKET,SO)REUSEADDR,&on,sizeof(on) < 0){
		ERR_LOG("fail to setsockopt");
	}
	
	//Step 2: Bind the socket to the server network information structure
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		ERR_LOG("fail to bind");
	}
	
	//Step 3: Set the socket to passive listening state
	if(listern(sockfd,10) == -1){
		perror("fail to listen");
		exit(1);
	}
	
	//Use signals to handle zombie processes asynchronously
	signal(SIGCHID,handler)
	
	while(1){
		//Step 4: Block waiting for client connection requests
		int acceptfd;
		struct sockaddr_in clientaddr;
		if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1){
			perror("fail to accept");
			exit(1);
		}
		//Print connected client information
		printf("ip:%s ,port: %d\n",inet_ntoa(clientaddr),ntohs(clientaddr.sin_port));
	
		//Create a child thread to communicate with the client
		MSG msg;
		msg.addr = clientaddr;
		msg.acceptfd = acceptfd;
		pthread_t thread;
		if(pthread_create(&thread,NULL,pthread_fun,&msg) != 0){
			ERR_LOG("fail to pthread_create");
		}
		pthread_detach(thread);	
		}
	}
	return 0;
}
1.7 Introduction to Web Server
1.7.1 Introduction to web server

Web server, also known as WWW server, website server, etc.

Features:
Exchange information with client browser using HTTP protocol
Not only store information, but also run scripts and programs based on information provided by the user through a web browser
The server can be installed on operating systems such as UNIX, Linux or Windows
Well-known servers include Apache, Tomcat, IIS, etc.

1.7.2 HTTP Protocol

Webserver—HTTP protocol (Hypertext Protocol)

Concept: A data transfer protocol that specifies the rules for mutual communication between browsers and web servers, and transmits web documents through the Internet

Features:
1. Support C/S architecture
2. Simple and fast: When a client requests a service from the server, it only needs to transmit the request method and path. Common methods: GET, POST
3. No connection: limit processing to only one request per connection

1.7.3 Webserver communication process
1.7.4 Web programming development

Web browsing (used GET method)

Client browse request

The ip address of the Web server is 192.168.3.103, the port number is 9999, and the webpage to be accessed is about.html

Data received by the server:

GET/index.html HTTP/1.1
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
Accept-Encoding:gzip,deflate

Format of the server response:

After the server receives the data sent by the browser, it needs to determine whether the webpage followed by GET/ exists. If it exists, the request is successful, and the specified command is sent, and the file content is sent to the browser. If it does not exist, the request fails to be sent.

request succeeded

"HTTP/1.1 200 OK\r\n"				\
"Content-Type: text/html\r\n"	\
"\r\n";

Request failed

"HTTP/1.1 404 Not Found\r\n"		\
"Content-Type: text/html\r\n"		\
"\r\n"							  \
"<HTML><BODY>File not found</BODY></HTML>"

Case:

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

//Implementing a TCP concurrent server using multiple processes

#define N 128
#define ERR_LOG(errmsg)do{\			perror(errmsg);\
						exit(1);\
						}while(0)

void *pthread_fun(void *arg){
	int acceptfd = *(int *)arg;
	char buf[N] = "";
	char head[] = "HTTP/1.1 200 OK\r\n"				\
				"Content-Type: text/html\r\n"		\
				"\r\n";
	char err[] = "HTTP/1.1 404 Not Found\r\n"		\
				"Content-Type: text/html\r\n"	\
				"\r\n"						\
				"<HTML><BODY>File not found</BODY></HTML>";
	//Receive data packets sent by the browser through the http protocol
	if(recv(acceptfd,buf,N,0) < 0){
		ERR_LOG("fail to recv");
	}
	
	printf("******************\n\n");
	printf("%s\n",buf);
	
	//Get the network file name to be accessed by the browser from the obtained data packet
	// GET /about.html http/1.1
	char filename[128] = "";
	sscanf(buf,"GET /%s",filename);   //The sscanf function ends with a space, so you can directly get the file name
	if(strncmp(filename,"HTTP/1.1",strlen("http/1.1")) == 0){
		strcpy(filename,"about.html");
	}
	printf("filename = %s\n",filename);
	
	char path[128] = "./sqlite/";
	strcat(path,filename);
	
	//By parsing the web page file name, find out whether there is this file locally
	int fd;
	if((fd = open(path,O_RDONLY)) < 0){
		//If the file does not exist, send the corresponding command that does not exist
		if(errno == ENOENT)
		{
			if(send(acceptfd,err,strlen(err),0) < 0){
				ERR_LOG("fail to send");
			}
			close(acceptfd);
			pthread_exit(NULL);
		}
		else{
			ERR_LOG("fail to open");
		}
	}
	
	//If the file exists, first send a command to tell the browser
	if(send(acceptfd,head,strlen(head),0) < 0){
		ERR_LOG("fail to send");
	}
	//Read the content of a web page file and send it to the browser
	ssize_t bytes;
	char text[1024] = "";
	while((bytes = read(fd,text,1024)) > 0){
		if(send(acceptfd,text,bytes,0) < 0){
			ERR_LOG("fail to send");
		}
	}
	pthread_exit(NULL);
}

int main(int argc, char **argv)
{
	if(argc < 3){
		fprintf(stderr,"UseageL %s [ip] [port]\n",argv[0]);
	}
	//Step 1: Create a TCP socket through the socket function
	int sockfd;
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		ERR_LOG("fail to socket");
	}
	
	//Set the socket to allow reuse of native addresses or set to port multiplexing
	int on = 1;
	if(setsockopt(sockfd,SOL_SOCKET,SO)REUSEADDR,&on,sizeof(on) < 0){
		ERR_LOG("fail to setsockopt");
	}
	
	//Step 2: Bind the socket to the server network information structure
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen) == -1)
	{
		ERR_LOG("fail to bind");
	}
	
	//Step 3: Set the socket to passive listening state
	if(listern(sockfd,10) == -1){
		perror("fail to listen");
		exit(1);
	}
	
	//Use signals to handle zombie processes asynchronously
	signal(SIGCHID,handler)
	
	while(1){
		//Step 4: Block waiting for client connection requests
		int acceptfd;
		struct sockaddr_in clientaddr;
		if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1){
			perror("fail to accept");
			exit(1);
		}
		//Print connected client information
		printf("ip:%s ,port: %d\n",inet_ntoa(clientaddr),ntohs(clientaddr.sin_port));
	
		//Create a child thread to communicate with the client
		MSG msg;
		msg.addr = clientaddr;
		msg.acceptfd = acceptfd;
		pthread_t thread;
		if(pthread_create(&thread,NULL,pthread_fun,&msg) != 0){
			ERR_LOG("fail to pthread_create");
		}
		pthread_detach(thread);	
		}
	}
	return 0;
}

Tags: TCP/IP server network

Posted by Stanza on Wed, 19 Oct 2022 03:38:21 +0530