Linux网络编程 Client/Server基础架构 框架设计思路

目录

一:C/S架构框架

二:Linux网络编程基础函数

三:C/S架构实现


一:C/S架构框架

基于流套接字的编程流程

计算机网络基础学习

二:Linux网络编程基础函数

C/S架构 【客户端Client 服务器Server】

查看socket使用说明

查看bind使用说明 

查看listen使用说明 

查看accept使用说明 

查看connect使用说明 

查看fork使用说明 (创建进程 进程间通信 服务器与客户端进程间通信)

测试计算机网络是否可用 计算机网卡是否损坏

ping 127.0.0.1 本机

三:C/S架构实现

服务器与客户端之间通信

(fork创建进程,accept阻塞,每有一个客户端上线才会frok创建一个进程,不需要传参,fork会拷贝代码)

(创建线程,acceptfd传参,每有一个客户端上线会创建一个线程,在后面的聊天系统案例中可以学习到)

对于聊天案例,多个客户端之间要实现互相聊天,就需要数据共享

对于fork创建进程,进程间的数据共享需要使用IPC技术,比较麻烦

在后面聊天系统开发,会使用到线程(进程包含线程,一个进程中的线程会共享该进程的资源,也就是可以数据共享),因此此篇文章的学习仅仅提供一个C/S架构网络概念,想要深入学习C/S架构开发,可以阅读博主后面的文章!

服务器实现 

#include<iostream>
#include <sys/types.h>         
#include <sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>

using namespace std;

int main()
{
	pid_t pid = 0;
	char buf[50] = { 0 };
	struct sockaddr_in addr;
	int len = 0;
	int acceptfd = 0;

	//初始化网络 识别当前计算机是否可以联网
    //第一个参数:采用IPV4 IP地址 第二个参数:网络分配TCP 
	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if (socketfd == -1)
	{
		perror("socket error");
	}
	else
	{
		cout << "socketfd = " << socketfd << endl;
		//确定用IPV4地址
		addr.sin_family = AF_INET;
		//服务器开放自己的IP地址给客户端连接使用   INADDR_ANY生成默认的可以联网的IP地址
		addr.sin_addr.s_addr = INADDR_ANY;
		//绑定服务器端口号0-65535  10000以下系统默认使用
		addr.sin_port = htons(10086);

		len = sizeof(addr);

		//bind 绑定ip地址 绑定端口号
		if (bind(socketfd, (struct sockaddr*)&addr, len) == -1)
		{
			perror("bind error");
		}

		if (listen(socketfd, 10) == -1)
		{
			perror("listen error");
		}

		cout << "网络搭建成功" << endl;

		while (1)
		{
			cout << "服务器等待客户端连接........." << endl;
			//服务器等待客户端连接 阻塞式函数 acceptfd在服务器代表已经连接成功的客户端
			acceptfd = accept(socketfd, NULL, NULL);

			cout << "有客户端成功连接 acceptfd = " << acceptfd << endl;

			pid = fork();
			if (pid == 0)
			{
				while (1)
				{
					int res = read(acceptfd, buf, sizeof(buf));
					cout << "服务器收到 res = " << res << "buf = "<<buf<< endl;
				}
			}
		}
	}
	return 0;
}

客户端实现 

#include<iostream>
#include <sys/types.h>         
#include <sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>

using namespace std;

int main()
{
	char buf[50] = { 0 };
	struct sockaddr_in addr;
	int len = 0;
	//初始化网络 识别当前计算机是否可以联网
	//第一个参数:采用IPV4 IP地址 第二个参数:网络分配TCP 
	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	cout << "客户端 socketfd = " << socketfd << endl;
	if (socketfd == -1)
	{
		perror("socket error");
	}
	else
	{
		//确定用IPV4地址
		addr.sin_family = AF_INET;
		//客户端主动寻找服务器IP地址 127.0.0.1本机回环地址 192.168.75.128
		addr.sin_addr.s_addr = inet_addr("192.168.75.128");
		//绑定服务器端口号0-65535  10000以下系统默认使用
		addr.sin_port = htons(10086);

		len = sizeof(addr);

		//主动去连接服务器 IP和端口
		if (connect(socketfd, (struct sockaddr*)&addr, len) == -1)
		{
			perror("connect error");
		}
		else
		{
			cout << "客户端连接服务器成功" << endl;
		}

		while (1)
		{
			cin >> buf;
			int res = write(socketfd, buf, sizeof(buf));
			cout << "客户端发送 res = " << res << endl;
			bzero(buf, sizeof(buf));
		}
	}

	return 0;
}

结果测试:

一个服务器 ,可以接收多个客户端发送过来的消息,实现了网络通信(进程间通信)

测试中可能出现问题:

如:客户端先下线【由于fork子进程拷贝父进程之前所有代码,acceptfd共用一块地址,当父进程先结束,子进程还在执行,此时造成孤儿进程,对于acceptfd的地址,在父进程结束的时候也没有了,因此子进程中acceptdf在read的时候就会出现错误,又因为使用while(1)因此,才有如下图一直读不到数据的情况】

解决:先关闭服务器 后关闭客户端

[但是在实际中其实服务器不能先关闭的,只能客户端下线]

对于客户端下线又分为两种情况:

客户端主动下线 & 客户端异常情况下线(如客户PC突然断点或蓝屏)

因此目前所搭建的C/S架构只是大致思路,需要做进一步改进的

测试中可能出现问题:

如关闭服务器后 再次运行服务器   

出现问题:bind error【因为在关闭服务器之后,端口号不会立即释放(端口号被占用),需要等个三五分钟,等待到端口号释放后就可再次使用端口号,建立C/S连接】

bind error 解决:需要等个三五分钟,再次运行服务器

对于以上问题的出现,是因为刚刚学习服务器客户端网络通信,目前的C/S架构还是稚嫩,在今后的学习中会将问题深入改进

此篇文章主要学习的是C/S架构设计流程

服务器 端口复用

客户端下线处理

对于以上两个问题,可以参考下面这篇文章解决

epoll IO多路复用技术 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenruhan_QAQ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值