天天看點

linux序列槽程式設計執行個體_linux網絡程式設計之TCP/IP的TCP socket通信過程(含執行個體代碼)

傳統的TCP/IP通信過程依賴于socket,位于應用層和傳輸層之間,使得應用程式可以進行通信。相當于港口城市的碼頭,使得城市之間可以進行貨物流通。伺服器和用戶端各有不同的通信流程。

一、伺服器

1、建立連接配接階段

調用socket(),配置設定檔案描述符,即監聽套接字

調用bind(),将套接字與本地IP位址和端口綁定

調用listen(),監聽特定端口,socket()建立的套接字是主動的,調用listen使得該檔案描述符為監聽套接字,變主動為被動

調用accept(),阻塞等待用戶端連接配接

2、資料互動階段

調用read(),阻塞等待用戶端發送的請求,收到請求後從read()傳回,處理用戶端請求

調用write(),将處理結果發送給用戶端,然後繼續調用read()等待用戶端請求

3、關閉連接配接

當read()傳回0的時候,說明用戶端發來了FIN資料包,即關閉連接配接,也會調用close()關閉連接配接套接字和監聽套接字

二、用戶端

1、建立連接配接階段

調用socket(),配置設定檔案描述符

調用connect(),向伺服器發送建立連接配接請求

2、資料互動階段

調用write(),将請求發送給伺服器

調用read(),阻塞等待伺服器應答

3、關閉連接配接

當沒有資料發送的時候,調用close()關閉連接配接套接字,即關閉連接配接,向伺服器發送FIN資料報

三、TCP通信過程

linux序列槽程式設計執行個體_linux網絡程式設計之TCP/IP的TCP socket通信過程(含執行個體代碼)

對tcp/ip網絡協定棧不熟悉的朋友可以看看這個視訊:手把手帶大家實作一個tcp/ip網絡協定棧

四、C語言代碼

伺服器端

/* File name: server.c*/
//伺服器端
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
 
#define MAXLINE 4096
#define PORT 8000
 
int main(void){
	//定義伺服器監聽套接字和連接配接套接字
	int listen_fd = -1, connect_fd = -1;//初始化為-1
	struct sockaddr_in servaddr;//定義伺服器對應的套接字位址
	//伺服器接收和發送緩沖區
	char sendbuf[MAXLINE], recbuf[MAXLINE];
 
	//初始化套接字位址結構體
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;//IPv4
	servaddr.sin_port = htons(PORT);//設定監聽端口
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//表示接收任意IP的連接配接請求
 
	//建立套接字
	if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
		//如果建立套接字失敗,傳回錯誤資訊
		//strerror(int errnum)擷取錯誤的描述字元串
		printf("create socket error: %s(error: %d)n", strerror(errno), errno);
		exit(0);
	}
 
	//綁定套接字和本地IP位址和端口
	if(bind(listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
		//綁定出現錯誤
		printf("bind socket error: %s(error: %d)n", strerror(errno), errno);
		exit(0);
	}
 
	//使得listen_fd變成監聽描述符
	if(listen(listen_fd, 10) == -1){
		printf("listen socket error: %s(error: %d)n", strerror(errno), errno);
		exit(0);
	}
 
	//accept阻塞等待用戶端請求
	printf("等待用戶端發起連接配接n");
 
	while(1){
		if((connect_fd = accept(listen_fd, (struct sockaddr*)NULL, NULL)) == -1){
			printf("accept socket error: %s(error: %d)n", strerror(errno), errno);
			continue;
		}
 
		//可以一直保持連接配接
		while(1){
			//讀取用戶端發來的資訊
			ssize_t len = read(connect_fd, recbuf, sizeof(recbuf));
			if(len < 0){
				if(errno == EINTR){
					continue;
				}
				exit(0);
			}
 
			printf("接收用戶端的請求:%sn", recbuf);
 
			//向用戶端發送資訊
			printf("回複用戶端資訊:");
			fgets(sendbuf, sizeof(sendbuf), stdin);
			write(connect_fd, sendbuf, sizeof(sendbuf));
		}
 
		//關閉連接配接套接字
		close(connect_fd);
	}
 
	//關閉監聽套接字
	close(listen_fd);
}
           

用戶端

/* File name: client.c */
//用戶端
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
 
#define MAXLINE 4096
#define PORT 8000
 
int main(void){
	//定義用戶端套接字
	int sockfd = -1;
	//定義想連接配接的伺服器的套接字位址
	struct sockaddr_in servaddr;
 
	//發送和接收資料的緩沖區
	char sendbuf[MAXLINE], recbuf[MAXLINE];
 
	//初始化伺服器套接字位址
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;//IPv4
	servaddr.sin_port = htons(PORT);//想連接配接的伺服器的端口
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//伺服器的IP位址
 
	//建立套接字
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
		printf("create socket error: %s(error: %d)n", strerror(errno), errno);
		exit(0);
	}
 
	//向伺服器發送連接配接請求
	if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
		//連接配接失敗
		printf("connect socket error: %s(error: %d)n", strerror(errno), errno);
		exit(0);
	}
 
	while(1){
		//向伺服器發送資訊
		printf("向伺服器發送資訊:");
		fgets(sendbuf, sizeof(sendbuf), stdin);
		write(sockfd, sendbuf, sizeof(sendbuf));
 
		//從伺服器接收資訊
		ssize_t len = read(sockfd, recbuf, sizeof(recbuf));
		if(len < 0){
			if(errno == EINTR){
				continue;
			}
			exit(0);
		}
 
		printf("伺服器回應:%sn", recbuf);
	}
 
	//關閉套接字
	close(sockfd);
 
}
           
需要C/C++ Linux伺服器架構師學習資料加qun擷取(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享
linux序列槽程式設計執行個體_linux網絡程式設計之TCP/IP的TCP socket通信過程(含執行個體代碼)