網絡編程:實現一個基於Linux的服務器端/客戶端程序

Linux下一切皆文件,socket套接字也不例外。socket是實現網絡數據傳輸的軟件設備,就像我們打電話的電話機一樣,是信息連接傳輸的通道。

socket定義的API提供兩點功能:

(1) 將應用程序數據從用戶緩衝區中複製到TCP/UDP內核發送緩衝區,以交付內核來發送數據,或者是從內核TCP/UDP接受緩衝區中複製數據到用戶緩衝區,以讀取數據。

(2)應用程序可以通過它們來修改內核中各層協議的某些頭部信息或其他數據結構,從而精細地控制底層通信的行爲。

socket是一套通用網絡編程接口,它不但可以訪問內核中TCP/IP協議棧,而且可以訪問其他網絡協議棧。

本文基於Linux實現一個簡單的服務器端/客戶端程序。

服務器端的基本實現流程爲:創建套接字、綁定地址、監聽端口、接受來自客戶端的連接,向客戶端發送數據,關閉套接字。

客戶端的基本實現流程爲:創建套接字,向服務器端發起連接請求,讀取服務器端的數據信息,關閉套接字。

以下是服務器端的代碼實現:

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
using namespace std;

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		cout << "usage: " << argv[0] << " <port>" << endl;
		exit(1);
	}

	int serv_sock;
	int clnt_sock;

	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;

	// 創建套接字
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1)
	{
		cout << "socket() error!" << endl;
		exit(1);
	}

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(atoi(argv[1]));

	// 綁定IP地址和端口號
	if (bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
	{
		cout << "bind() error!" << endl;
		exit(1);
	}

	// 在IP和端口上進行監聽
	if (listen(serv_sock, 5) == -1)
	{
		cout << "listen() error!" << endl;
		exit(1);
	}

	// 接收來自客戶端的連接請求
	clnt_addr_size = sizeof(clnt_addr);
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	if (clnt_sock == -1)
	{
		cout << "accpet() error!" << endl;
		exit(1);
	}

	// 向客戶端發送數據
	char message[] = "Hello client, it's server!";
	write(clnt_sock, message, sizeof(message));
	
	// 關閉套接字
	close(clnt_sock);
	close(serv_sock);

	return 0;
}

以下是客戶端的代碼實現:

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
using namespace std;

int main(int argc, char* argv[])
{
	if (argc != 3)
	{
		cout << "usage: " << argv[0] << " <IP> <port>" << endl;
		exit(1);
	}

	int sock;
	struct sockaddr_in serv_addr;

	// 創建套接字
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
	{
		cout << "socket() error!" << endl;
		exit(1);
	}

	// 初始化地址信息
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));

	// 向服務器端發起連接請求
	if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
	{
		cout << "connect() error!" << endl;
		exit(1);
	}

	// 讀取來自服務器端的數據
	char message[100];
	int str_len = read(sock, message, sizeof(message) - 1);
	if (str_len == -2)
	{
		cout << "read() error!" << endl;
		exit(1);
	}
	cout << "Message from server: " << message << endl;

	// 關閉套接字
	close(sock);
	return 0;
}

在Linux下使用g++進行編譯,編譯命令爲:

g++ servce.cpp -o serve
g++ client.cpp -o client

生成可執行文件serve/client,然後開啓兩個終端,分別執行客戶端程序和服務器端程序。

以下是服務器端的執行結果:在8888端口進行監聽,客戶端連接之前進行等待,連接成功之後,向客戶端發送信息,然後關閉套接字,程序結束
在這裏插入圖片描述

以下是客戶端的執行結果:向本地IP和8888端口請求連接,連接成功後,讀取服務器端發送來的數據,並打印,然後關閉套接字,程序結束。
在這裏插入圖片描述

感謝閱讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章