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👇

