計算機網絡|C語言Socket編程,實現兩個程序間的通信


C語言Socket編程,實現兩個程序間的通信

server和client通信流程圖

在mooc上找到的,使用Socket客戶端client和服務端server通信的流程圖👇




不一定只用codeblock,用devcpp編譯器也可以的,需要很簡單的配置一下編譯環境



先理解原理: https://blog.csdn.net/jinmie0193/article/details/78951055

實現兩個程序間的通信

1.服務端server

  • 服務端需要 "兩個"套接字 :

    • 1.服務端套接字serverSocket
    • 2.客戶端connect連接請求時,發來的套接字clientSocket

  • 按流程圖來看, server服務端主要就是實現下面幾個步驟:

    • 0.WSAStartup初始化 //這個東西也不知道是什么鬼,反正就是要初始化一下,不初始化會創建socket失敗!
    • 1.服務端套接字 = socket(); //獲取一個套接字對象吧?
    • 2.bind(服務端套接字); //綁定
    • 3.listen(服務端套接字); //監聽
      ---這個時候客戶端就可以發連接請求到服務端了,此時服務端會用accept阻塞進程,直到獲取客戶端發來的請求---
    • 4.客戶端套接字 = accept(); //收到客戶端發來的請求,accept返回客戶端的套接字對象
    • 5.recv(客戶端套接字,要發的消息message) //recv會阻塞進程,直到客戶端發送消息過來
      ----printf(message)把接收到的消息打印出來-----
    • 6.send(客戶端套接字,要發的消息message) //服務端也可以使用send,向客戶端發送消息
      ---這里可以循環,跳轉回到步驟3.accept 開啟新一輪的接收請求---
    • 7.closesocket(客戶端套接字);

所以服務端代碼可以這樣寫👇
在CSDN上copy的,原來的代碼需要在linux環境下運行,在windows下需要更改很多頭文件,和一些函數,wsastartup這個東西也需要初始化一下。
改了之后,一個可以用的服務端server代碼👇


#include <sys/stat.h>
#include <fcntl.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "wsock32.lib")
#include <errno.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include<ws2tcpip.h>
#include <stdio.h>
#include <unistd.h>
#define SERVER_PORT 6666
 
/*
監聽后,一直處於accept阻塞狀態,
直到有客戶端連接,
當客戶端如數quit后,斷開與客戶端的連接
*/
 
int main()
{
 
	//調用socket函數返回的文件描述符
	int serverSocket;
	 
	//聲明兩個套接字sockaddr_in結構體變量,分別表示客戶端和服務器
	struct sockaddr_in server_addr;
	struct sockaddr_in clientAddr;
	 
	int addr_len = sizeof(clientAddr);
	int client;
	char buffer[200]; //存儲 發送和接收的信息 
	int iDataNum;

	//必須先初始化 
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2),&wsaData);
	if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) !=2){
	    printf("require version fail!");
	    return -1;
	}
	
	//socket函數,失敗返回-1
	//int socket(int domain, int type, int protocol);
	//第一個參數表示使用的地址類型,一般都是ipv4,AF_INET
	//第二個參數表示套接字類型:tcp:面向連接的穩定數據傳輸SOCK_STREAM
	//第三個參數設置為0
	//建立socket
	if((serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{
		perror("socket");
		return 1;
	}
	
	//初始化 server_addr
	memset(&server_addr,0, sizeof(server_addr));
	 
	//初始化服務器端的套接字,並用htons和htonl將端口和地址轉成網絡字節序
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
	 
	//ip可是是本服務器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	 
	//對於bind,accept之類的函數,里面套接字參數都是需要強制轉換成(struct sockaddr *)
	//bind三個參數:服務器端的套接字的文件描述符,
	if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
	{
		perror("connect");
		return 1;
	}
	 
	//設置服務器上的socket為監聽狀態
	if(listen(serverSocket, 5) < 0)
	{
		perror("listen");
		return 1;
	}
	
	//循環 接收消息、發送消息 
	while(1)
	{ 
		printf("監聽端口: %d\n", SERVER_PORT);
		
		//調用accept函數后,會進入阻塞狀態
		//accept返回一個套接字的文件描述符,這樣服務器端便有兩個套接字的文件描述符,
		//serverSocket和client。
		//serverSocket仍然繼續在監聽狀態,client則負責接收和發送數據
		//clientAddr是一個傳出參數,accept返回時,傳出客戶端的地址和端口號
		//addr_len是一個傳入-傳出參數,傳入的是調用者提供的緩沖區的clientAddr的長度,以避免緩沖區溢出。
		//傳出的是客戶端地址結構體的實際長度。
		//出錯返回-1
		
		client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
		
		if(client < 0)
		{
			perror("accept");
			continue;
		}
		 
		printf("等待消息...\n");
		
		//inet_ntoa ip地址轉換函數,將網絡字節序IP轉換為點分十進制IP
		//表達式:char *inet_ntoa (struct in_addr);
		printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr)); //把來訪問的客戶端的IP地址打出來
		printf("Port is %d\n", htons(clientAddr.sin_port)); 
		 
		while(1)
		{
			buffer[0] = '\0';
			iDataNum = recv(client, buffer, 1024, 0);
			if(iDataNum < 0)
			{
	//			perror("recv null");
				continue;
			}
			buffer[iDataNum] = '\0';
			if(strcmp(buffer, "quit") == 0) break;
			printf("收到消息: %s\n", buffer);
			printf("發送消息:");
			scanf("%s", buffer);
			send(client, buffer, strlen(buffer), 0); //服務端也向客戶端發送消息 
			if(strcmp(buffer, "quit") == 0) break; //輸入quit停止服務端程序 
		}
	}
	 
	close(serverSocket);
	 
	return 0;
 
}

2.客戶端client

  • 客戶端只需要 "1個"套接字 :

    • 1.服務端套接字serverSocket
  • 按流程圖來看, client客戶端主要就是實現下面幾個步驟:

    • 0.WSAStartup初始化 //這個東西也不知道是什么鬼,反正就是要初始化一下,不初始化會創建socket失敗!
    • 1.服務端套接字 = socket(); //獲取一個套接字對象
    • 2.connect(服務端套接字); //connect連接服務端
      ---這個時候客戶端就可以發數據到服務端了,此時服務端會用recv阻塞進程,直到獲取客戶端發來的數據---
    • 3.send(服務端套接字,要發的消息message)
    • 4.recv(服務端套接字,收到的message) //客戶也可以用recv收消息的,recv會阻塞進程,直到服務端發送消息過來
      ---printf(message)把接收到的消息打印出來---
      ---這里可以循環,跳轉回到步驟3.send 開啟新一輪的接收請求---
    • 5.closesocket(客戶端套接字);

也是在CSDN上copy的代碼,改了之后,一個可以用的客戶端client代碼👇

#include <sys/stat.h>
#include <fcntl.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "wsock32.lib")
#include <errno.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include<ws2tcpip.h>
#include <stdio.h>
#include <unistd.h>
#define SERVER_PORT 6666
 
int main()
{
 
	//客戶端只需要一個套接字文件描述符,用於和服務器通信
	int serverSocket;
	 
	//描述服務器的socket
	struct sockaddr_in serverAddr;
	 
	char sendbuf[200]; //存儲 發送的信息 
	char recvbuf[200]; //存儲 接收到的信息 
	 
	int iDataNum;
	
	//下面代碼初始化 
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2),&wsaData);
	if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) !=2){
	    printf("require version fail!");
	    return -1;
	}
	
	if((serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{
		perror("socket");
		return 1;
	}
	 
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(SERVER_PORT);
	 
	//指定服務器端的ip,本地測試:127.0.0.1
	//inet_addr()函數,將點分十進制IP轉換成網絡字節序IP
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	 
	if(connect(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
	{
		perror("connect");
		return 1;
	}
	 
	printf("連接到主機...\n");
	 
	while(1)
	{
		printf("發送消息:");
		scanf("%s", sendbuf);
		printf("\n");
		send(serverSocket, sendbuf, strlen(sendbuf), 0); //向服務端發送消息
		if(strcmp(sendbuf, "quit") == 0) break;
		printf("讀取消息:");
		recvbuf[0] = '\0';
		iDataNum = recv(serverSocket, recvbuf, 200, 0); //接收服務端發來的消息
		recvbuf[iDataNum] = '\0';
		printf("%s\n", recvbuf);
	}

	close(serverSocket);
 
	return 0;
}


3.怎么運行呢?

首先編譯server.c和client.c這兩個c語言,build-compile成.exe文件
用devcpp編譯器也可以編譯的,不一定一定要用codeblock。。
如果用devcpp上面的代碼編譯出錯,需要把devcpp設置一下編譯選項,參考鏈接

主要運行步驟👇

0.確認程序已經編譯成功生成了exe文件。
1.先運行服務端server.exe
2.再運行客戶端client.exe
3.就可以在client程序里輸入消息到服務端了,服務端會收到消息,也能向客戶端發消息

這里可以用一下cmd命令符打開運行文件👇
運行---->cmd

打開cmd,運行server服務端程序

D:                  //先進入程序存放的磁盤,比如 D: 或者 C: 或者 F:
cd fishers  //cd C語言程序服務端server所在的目錄,比如cd 2017xxx/MyTest
server   //直接輸入服務端程序的名稱,運行server.exe程序,

打開cmd,運行client客戶端程序

D:                  //先進入程序存放的磁盤,比如 D: 或者 C: 或者 F:
cd fishers  //cd C語言程序客戶端client所在的目錄,比如cd 2017xxx/MyTest
client   //直接輸入客戶端程序的名稱,運行client.exe程序

然后就可以在client上輸入想要發送的消息了👇

按步驟來的視頻,配置編譯器,編譯,運行server.exe,運行client.exe,發消息👇



主要是理解客戶端和服務端通信的流程



4.重寫代碼

然后上面是CSDN的代碼,理解原理后就可以自己改寫server.c和client.c,實現兩個程序間基於socket的通信

理解原理:https://blog.csdn.net/jinmie0193/article/details/78951055


server.c👇





client.c👇




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM