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