网络编程:实现一个基于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端口请求连接,连接成功后,读取服务器端发送来的数据,并打印,然后关闭套接字,程序结束。
在这里插入图片描述

感谢阅读

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