在Linux中利用C語言構建TCP網絡通信實現服務器和客戶端的通信

我們都知道,TCP通信是面向對象,可靠的連接服務,故TCP通信節點在軟件設計中被廣泛應用,因此這裏實現構建一個簡單的TCP通信節點demo

  • 軟件環境: deepin 5.11

1.服務端構建

1)socket() – 創建通信套接字

	//1.創建套接字 --- socket()
	/*
	int socket(int domain, int type, int protocol);
	參數: domain --- AF_INET  地址族
		  type   --- 套接字類型 
		  SOCK_STREAM(流式套接字)
		  protocol --- 0
	*/
	
	int sockfd = socket(AF_INET,SOCK_STREAM,0);		//返回值0爲成功,-1爲失敗
	if(sockfd == -1)
	{
		perror("socket");			//打印錯誤輸出
		return -1;	 
	}
	printf("socket excute successful!\n");

2)bind() – 綁定套接字

	//2綁定套接字 --- bind()
	/*
	int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
	參數: sockfd  ——-- 套接字文件描述符
		  addr   ---  通用地址結構
		  addrlen --- 地址的長度
	*/		

	struct sockaddr_in myaddr;                //IPV4地址結構體
	memset(&myaddr, 0, sizeof(myaddr));
	myaddr.sin_family = AF_INET;              
	myaddr.sin_port = htons(8888);           //自定義設置端口號   5001~65535
	myaddr.sin_addr.s_addr = inet_addr("192.168.3.121");  //自定義設置爲此服務器所在的IP地址
	
	if (bind(sockfd, (struct sockaddr*)&myaddr, sizeof(myaddr)) == -1)						//0成功 -1失敗
    {
		perror("bind");
		return -1;
	}
	printf("bind success!\n"); 

3)listen() – 設置監聽套接字

	//3設置監聽套接字 --- listen()
	/*
	int listen(int sockfd, int backlog);
	參數: sockfd --- 套接字文件描述符
	       backlog -- 監聽隊列的長度
	*/ 

	if(listen(sockfd,5) == -1)
	{
		perror("listen");
		return -1;	//返回現在執行的函數(結束函數) 
	}
	printf("listen successful!\n"); 

4) accept() – 接受客戶端的連接

	//4等待客戶端的連接 --- accept()
    /*
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
		參數: sockfd --- 套接字文件描述符
                       第二/三個參數設置爲NULL
    */

	int connfd = accept(sockfd,NULL,NULL);
	if(connfd == -1)
	{
		perror("accpet!");
		return -1;	//返回現在執行的函數(結束函	
	}
	printf("accpet success!\n");

5) read() – 服務端收數據

	//5收來自客戶端的數據 --- read()
	/*
	ssize_t read(int fd, void *buf, size_t count);
	 參數:fd --- 文件描述符
		  buf --- 緩衝區首地址
		  count --- 想要讀取的字節數
	返回值: 
			成功: >0  --- 成功讀取的字節數
				  =0  --- 讀到文件末尾
			失敗: -1  --- 設置errno
	*/

	char buf[1024];
	while(1)
	{
		memset(buf,0,sizeof(buf));		//將 buf空間中的1024內容清空 
		 
		read(connefd,buf,sizeof(buf));	//表示把buf中的呢熊讀入 
		int ret = read(connefd,buf,sizeof(buf));
		if(ret == -1)			//讀取失敗 
		{	
			perror("read!");
			break;
		}
		else if(ret == 0)		//寫端口關閉 
		{
			printf("client close\n")
		}
		else				   //成功接收
		{
			printf("recv : %s\n");
		 } 
		 if (0 == strcmp(buf, "exit"))	//判斷是否退出
			break;
		
		//添加客戶端和服務端信息交互
		printf("send: ");
		fgets(buf,1024,stdin);
		ret = write(connfd, buf, sizeof(buf));
		if (ret == -1) {
			perror("write");
			break;
		}
		if (strcnmp(buf, "exit",4) == 0)
			break;
	}

6) close() – 關閉套接字

	//6關閉套接字 --- close()
	close(connfd);			//關閉連接
	close(sockfd);			//關閉文件描述符

2.客戶端構建

客戶端的構建原理方式,步驟和服務端大似相同

1)socket() – 創建套接字

	//1.創建套接字
	int sockfd = socket(AF_INET,SOCK_STREAM,0);		
	if(sockfd == -1)
	{
		perror("socket");
		return -1;	
	}
	printf("socket excute successful!\n");

2)connect() – 主動連接服務器

原理步驟和綁定服務器設置相同

	//2.連接服務器
	struct sockaddr_in myaddr;                //IPV4地址結構體
	memset(&myaddr, 0, sizeof(myaddr));
	srvaddr.sin_family = AF_INET;              
	srvaddr.sin_port = htons(8888);           //端口號   5001~65535
	srvaddr.sin_addr.s_addr = inet_addr("192.168.3.121");  //設置IP地址
	
	if (-1 == connect(sockfd, (struct sockaddr*)&myaddr, sizeof(myaddr))) {
		perror("bind");
		return -1;
	}
	printf("bind success!\n"); 

3)write() – 發數據

	//3.發數據
	char buf[1024];
	int ret;
	while(1)	//循環從鍵盤輸入串 
	{
		printf("send : ");
		fget(buf,1024,stdin);		//輸入字符串並存入buf 
		ret = write(sockfd,buf,sizeof(buf));
		if(ret == -1)
		{
			perror("write");
			break;
		}
		if (strncmp(buf, "exit",4) == 0)	
			break;

		ret = read(sockfd, buf, sizeof(buf));
		if (ret == -1) {
			perror("read");
			break;
		}else if (0 == ret) {
			printf("server close!\n");
			break;
		}
		printf("recv: %s\n", buf);
		if (strcnmp(buf,"exit",4 ) == 0)
			break;
	}

4)close() – 關閉套接字

//4.關閉
close(sockfd);

3.效果展示

在這裏插入圖片描述

4.全部代碼

  • 服務端
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
			
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>


int main()
{
	//1創建套接字
	//man socket查看手冊 
	int sockfd = socket(AF_INET,SOCK_STREAM,0);		 
	if(sockfd == -1)
	{
		perror("socket");
		return -1;	
	}
	printf("socket excute successful!\n"); 
	
	//2綁定套接字
	struct sockaddr_in myaddr;                //IPV4地址結構體
	memset(&myaddr, 0, sizeof(myaddr));
	myaddr.sin_family = AF_INET;              
	myaddr.sin_port = htons(8888);           //端口號   5001~65535
	myaddr.sin_addr.s_addr = inet_addr("192.168.232.130");  //設置IP地址
	
	if (-1 == bind(sockfd, (struct sockaddr*)&myaddr, sizeof(myaddr))) {
		perror("bind");	
		return -1;
	}
	printf("bind success!\n"); 
	
	//3設置監聽套接字
	if(listen(sockfd,5) == -1)
	{
		perror("listen");
		return -1;	//返回現在執行的函數(結束函數) 
	}
	printf("listen successful!\n"); 
	
	//4接受客戶端的連接。並生成新的通信套接字
	//accpet() 
	int connfd = accept(sockfd,NULL,NULL);			//定義套接字
	if(connfd == -1)
	{
		perror("accpet!");
		return -1;	//返回現在執行的函數(結束函	
	}
	printf("accpet success!\n");
	
	//5收數據
	char buf[1024];
	while(1)
	{
		memset(buf,0,sizeof(buf));		//將 buf空間中的1024內容清空 
		int ret = read(connfd,buf,sizeof(buf));
		if(ret == -1)			//讀取失敗 
		{	
			perror("read!");
			break;
		}
		else if(ret == 0)		//寫端口關閉 
		{
			printf("client close\n");
		}
		else
		{
			printf("recv : %s\n");
		 } 
		 if (0 == strncmp(buf, "exit",4))	//判斷是否退出
			break;
		
		//添加客戶端和服務端信息交互
		printf("send: ");
		fgets(buf,1024,stdin);
		ret = write(connfd, buf, sizeof(buf));
		if (ret == -1) {
			perror("write");
			break;
		}
		if (strcnmp(buf, "exit",4) == 0)
			break;
	}
	
	
	//6關閉套接字 
	close(connfd);
	close(sockfd);
	 
	
	return 0;
 } 
  • 客戶端
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
			
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main()
{
	//1.創建套接字
	//socket();
	int sockfd = socket(AF_INET,SOCK_STREAM,0);		
	if(sockfd == -1)
	{
		perror("socket");
		return -1;	//返回現在執行的函數(結束函數) 
	}
	printf("socket excute successful!\n");
	
	
	//2. 主動連接服務器
	//connect();
	struct sockaddr_in srvaddr;                //IPV4地址結構體
	memset(&srvaddr, 0, sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;              
	srvaddr.sin_port = htons(8888);           //端口號   5001~65535
	srvaddr.sin_addr.s_addr = inet_addr("192.168.232.130");  //鏈接服務器的IP地址
	
	if (-1 == connect(sockfd, (struct sockaddr*)&srvaddr, sizeof(srvaddr))) {
		perror("bind");
		return -1;
	}
	printf("bind success!\n"); 
	
	
	//3.發數據
	//write()
	char buf[1024];
	int ret;
	while (1) {
		printf("send: ");
		fgets(buf,1024,stdin);   
		ret = write(sockfd, buf, sizeof(buf));
		if (-1 == ret) {
			perror("write");
			break;
		}
		if (strncmp(buf, "exit",4) == 0)		//判斷是否退出
			break;

		ret = read(sockfd, buf, sizeof(buf));
		if (ret == -1) {
			perror("read");
			break;
		}else if (0 == ret) {
			printf("server close!\n");
			break;
		}
		printf("recv: %s\n", buf);
		if (strncmp(buf,"exit",4) == 0)
			break;
	}
	
	
	//4.關閉套接字
	close(sockfd); 
	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章