TCP/IP protocol
TCP/IP protocol stack is the sum of a series of network protocols. It is the core framework of network communication. It defines how electronic devices connect to the Internet and how data is transmitted between them.
Correspondence between OSI 7-layer model and TCP/IP 4-layer network model
![](/images/doc/cb629722a747102f337c0312653cb0c1.jpg)
The basic knowledge of computer network is not enough to explain, mainly to let everyone understand which layer the next Linux network programming data flow belongs to, as shown in the figure below
![](/images/doc/c8714f8e245b4e738b2af32d28c27c9a.jpg)
TCP/IP protocol data flow diagram
The Tcp protocol of Linux network programming we will explain next is a protocol belonging to the transport layer
Linux Socket network programming
TCP protocol
TCP is a reliable connection oriented transport layer protocol.
TCP programming
Network programming in Linux is carried out through socket interface. Socket is a special I/O interface and a file descriptor. It is often used for communication between processes on different machines. Of course, it can also realize communication between processes on local machines.
Flow chart of using TCP protocol
![](/images/doc/62832b8e34e779e2d67cc281de38546d.jpg)
Explain API interfaces one by one according to the flow chart
Server API interface
socket
#include <sys/socket.h> int socket(int family //Protocol cluster general AF_INET PF_INET ,int type //Socket type sock_ Stream (byte stream socket interface) ,int protocol); //Non original socket, parameter 0
Socket type:
- SOCK_ Stream (byte stream socket interface)
- SOCK_ Dgram (datagram socket interface)
- SOCK_ Raw (original socket)
Example:
listenfd = socket(AF_INET,SOCK_STREAM,0);
bind
Assign a local IP and protocol port to the socket
#include <sys/socket.h> int bind(int socket , const struct sockaddr *address//Protocol family address ,socklen_t address_len); //Protocol family length
-Address: protocol family address, general socket address
The general socket address is not easy to use, so Linux provides a special socket address structure for each protocol family
UNIX native protocol family
struct sockaddr_un { sa_family_t sa_family; char sun_path[100]; }
TCP/IP protocol family
The TCP/IP protocol family has sockaddr_in and sockaddr_in6 two dedicated socket address structures, corresponding to IPv4 and IPv6 respectively
Protocol family SOCKADDR corresponding to IPv4_ In is defined as follows
struct sockaddr_in { sa_family_t sin_family; /*Address family: AF_INET*/ in_port_t sin_port; /*Port number in network byte order*/ struct in_addr sin_addr; /*ipv4 address*/ }
/* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };
ipv6 is rarely used, so the definition is not introduced separately
Commonly used are sockaddr_ In (network address), sockaddr_ UN (local address), which is cast to sockaddr * pointer type when passing in parameters. The example is as follows.
struct sockaddr_in servaddr; /*(2) Set the server protocol family sockaddr_in structure*/ bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET;//Must be consistent with the creation fimile of the socket servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//Indicates that any IP address is acceptable servaddr.sin_port = htons(8888); bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
listen
The listen function is only called by the TCP server
#include <sys/socket.h> int listen(int sockfd //Socket description returned by socket function ,int backlog); //This value indicates the queue size and the maximum number of connections when listen ing
listen(listenfd,2);
accept
#include <sys/socket.h> int accept(int listenfd //Socket function returns socket descriptor listener handle , struct sockaddr *client //Protocol family address , socklen_t * addrlen); //Client socket
accept(listenfd , (struct sockaddr *)&cliaddr , &clilen);
Used to receive a new connection.
Client API interface
connect
#include <sys/socket.h> int connect(int sockfd , const struct sockaddr * addr //Protocol family address , socklen_t addrlen); //Protocol family length
connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))
Used to connect to the server
send/recv
#include <sys/types.h> #include < sys/socket.h > ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t recv(int sockfd, void *buf, size_t len, int flags);
The first three parameters are the same as read(). The parameter flags is the transmission control flag. UDP will be introduced in detail
TCP case
Server
#include<stdio.h> #include<stdlib.h> #include<sys/socket.h> #include<sys/types.h> #include<unistd.h> #include<string.h> #include<netinet/in.h> #include<netdb.h> #include<arpa/inet.h> #define MAX_BUFF 1024 #define MAX_LISTEN 10 int main(int argc,char *argv[]) { int defaule_port = 8000; int optch = 0; while((optch = getopt(argc, argv, "s:p:")) != -1) { switch (optch) { case 'p': defaule_port = atoi(optarg); printf("port: %s\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; default: break; } } /*Declare server address and client link address*/ struct sockaddr_in server_addr,client_addr; socklen_t client_len; /*Declare server listening socket and client link SOCKET*/ int listen_fd,connect_fd; /*(1) Initialize listening socket listenfd*/ listen_fd = socket(AF_INET, SOCK_STREAM,0); if(listen_fd == -1) { perror("Socket Error:"); return 0; } /*(2) Set up server sockaddr_in structure*/ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //Any address server_addr.sin_port = htons(defaule_port); /*(3) Binding sockets and ports*/ if(bind(listen_fd,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1) { perror("Bind error:"); return 0; } /*(4) Listen to customer requests*/ if(listen(listen_fd,MAX_LISTEN)==-1) { perror("Listen error:"); return 0; } /*(5) Accept customer requests*/ for(;;) { client_len = sizeof(client_addr); connect_fd = accept(listen_fd,(struct sockaddr*)&client_addr,&client_len); if(connect_fd < 0) { perror("accept error"); return 0; } printf("Connect from %s:%u...\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); /*Declare the buffer and send data to the client*/ char buff[MAX_BUFF] = "hello\n"; if(-1 == write(connect_fd,buff,strlen(buff))) { perror("Send error\n"); return 0; } printf("Send success...\n"); /*Empty the buffer and block the data sent by the client waiting to be read*/ memset(buff,'\0',sizeof(buff)); if(-1 == read(connect_fd,buff,MAX_BUFF)) { perror("read error\n"); return 0; } write(1,buff,strlen(buff)); close(connect_fd); } close(listen_fd); return 0; }
Compile and run. The default port is 8000, - p specify the port
gcc -o server.c server ./server -p 8020
client
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> const int MAX_LINE = 2048; int main(int argc ,char**argv) { /*Declare socket and linked server addresses*/ int sockfd; int optch,ret = -1; const char*server_addr; int default_port = 8000; struct sockaddr_in servaddr; /*To judge whether it is a legal input, you must pass in a parameter: server Ip*/ if(argc<3) { printf("usage:tcpcli <IPaddress>"); return 0; } while((optch = getopt(argc, argv, "s:p:")) != -1) { switch (optch) { case 's': server_addr = optarg; break; case 'p': default_port = atoi(optarg); printf("port: %s\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; default: break; } } /*(1) Create socket*/ sockfd =socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { perror("socket error"); return 0; } /*(2) Set up linked server address structure*/ bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family =AF_INET; servaddr.sin_port = htons(default_port); if(inet_pton(AF_INET , server_addr , &servaddr.sin_addr) < 0) { printf("inet_pton error for %s\n",server_addr); return 0; } /* (3) Send link server request */ if( (ret = connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))) < 0) { perror("connect error"); return 0; } printf("connect seccess,ret:%d..\n",ret); struct sockaddr_in c_addr; memset(&c_addr, 0, sizeof(c_addr)); socklen_t len = sizeof(c_addr); char buf[MAX_LINE]; while (1) { /* code */ memset(buf,'\0',sizeof(buf)); len = read(sockfd,buf,sizeof(buf)-1); if(len == 0) { printf("server close..\n"); return 0; } printf("recv from server:%s",buf); memset(buf,'\0',sizeof(buf)); printf("please enter:\n"); ssize_t len = read(0,buf,sizeof(buf)-1); if(len>0) { if(strcmp(buf,"quit")==0) { printf("quit\n"); break; } buf[len - 1]='\0'; write(sockfd,buf,strlen(buf)); } } close(sockfd); return 0; }
Compile and run. The default port is 8000, - s specifies the connected server, - p specifies the port
$ gcc -o client client.c $ ./client -s 0.0.0.0 -p 8020 connect seccess,ret:0.. recv from server:hello please enter: hello too server close..
That's all for the simple tcp server and client. The next issue introduces multithreading technology to realize a multithreaded chat room program.