IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 网络编程——C/S模型 -> 正文阅读

[网络协议]网络编程——C/S模型

目录

TCP介绍

C/S模型框架

Server端

1.创建套接字

2.绑定IP地址和端口号

3.使用该套接字监听连接请求

4.当请求来到时,调用accept函数复制该套接字处理请求

5.数据通信

client端

? ? ? ? 1.创建套接字

? ? ? ? 2.使用创建好的套接字向服务端发送连接请求

? ? ? ? 3.利用套接字进行数据的通信

server端简单示例代码

client端简单示例代码

存在的问题


TCP介绍

TCP:传输控制协议,提供面向连接的,一对一的可靠数据传输协议。

TCP特点:能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。

TCP适用情况:

  1. 适合于对传输质量要求比较高,以及传输大量数据的通信。
  2. 在需要可靠数据传输的场合,通常适用TCP协议。
  3. MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议。

C/S模型框架

Server端

1.创建套接字

? ? ? ??int socket(int domain, int type, int protocol);

????????该套接字是后面用来监听客户端请求的套接字。

2.绑定IP地址和端口号

? ? ? ???int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

? ? ? ? 该函数在填写addr参数时,要注意,我们先填写struct sockaddr_in这个结构体,再传递参数时,要将sockaddr_in类型的指针强转成sockaddr类型的指针。

? ? ? ? 注意:网络字节序和本地字节序的切换。

端口:

????????uint32_t htonl(uint32_t hostlong);

? ? ? ?uint16_t htons(uint16_t hostshort);

? ? ? ?uint32_t ntohl(uint32_t netlong);

? ? ? ?uint16_t ntohs(uint16_t netshort);

ip地址:

????????in_addr_t inet_addr(const char *cp);

????????int inet_pton(int af, const char *src, void *dst);

????????const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);

3.使用该套接字监听连接请求

????????int listen(int sockfd, int backlog);

? ? ? ? socket创建的套接字是一个主动套接字,也就是说是主动连接别人的一个套接字。listen函数将一个未连接的套接字转换成了一个被动套接字,等待连接。调用listen使套接字从closed状态转换成了listen状态。

4.当请求来到时,调用accept函数复制该套接字处理请求

????????int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

? ? ? ? 一般我们将函数第一个参数称为监听套接字,将函数返回的套接字称为已连接套接字。一个服务器只有一个监听套接字,监听客户端的连接请求。服务器内核为每一个客户端的TCP连接维护1个已连接套接字,用它实现数据双向通信。

5.数据通信

? ? ? ? 利用accept返回的套接字,进行数据的通信。也就是IO操作了。

client端

? ? ? ? 1.创建套接字

? ? ? ? ? ? ? ? 同TCP

? ? ? ? 该套接字是用来向服务器发送请求的套接字。

? ? ? ? 2.使用创建好的套接字向服务端发送连接请求

????????int connect(int sockfd, const struct sockaddr *addr,?socklen_t addrlen);

? ? ? ? 该函数第二个参数是一个结构体,该结构体中保存着发送连接请求对象的ip地址和端口号。

? ? ? ? 3.利用套接字进行数据的通信

server端简单示例代码

int main(int argc, const char *argv[])
{
	int fd = -1;
	struct sockaddr_in sin;
	int ret ;
	/*1.创建socket套接子*/
	if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("socket");
		exit(1);
	}
	/*2.bind绑定,绑定之前填充sockaddr_in这个结构体*/
			/*2.1   sin_zero 后八位要全部置零*/
	bzero(&sin,sizeof(sin));
			/*2.2   域指定IPV4编程*/
	sin.sin_family = AF_INET;
			/*2.3   填写端口号*/
	sin.sin_port = htons(5001);
			/*2.4   将网络地址填写到sin.sin_addr.s_addr中*/
	sin.sin_addr.s_addr = inet_addr("192.168.1.3"); /*inet_addr函数只适用于IPV4*/
	
#if 0
    inet_pton(AF_INET,"127.0.0.1",(void *)&sin.sin_addr.s_addr);/*inet_pton可以使用IPV6*/
#endif	

#if 0	
    sin.sin_addr.s_addr = htonl(INADDR_ANY);   
    /*只需绑定INADDR_ANY,管理一个套接字就行,不管数据是从哪个网卡过来的,只要是绑定的端口号过来的数据,都可以接收到。*/
#endif

            /*2.5 最后进行绑定*/
	if(bind(fd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		perror("bind");
		exit(1);
	}
 	
	/*3.listen 把主动套接子变成被动套接子*/
	if(listen(fd,5) < 0)
	{
		perror("listen");
		exit(1);
	}
	/*4.阻塞等待客户端链接请求*/
	int newfd = -1;
	newfd = accept(fd,NULL,NULL);   /*两个NULL 不关心客户端的ip和端口号,所以就NULL*/
	if(newfd < 0)
	{
		perror("accept");
		exit(1);
	}
	/*5.读写*/
	ret = -1;
	char buf[255];
	while(1)
	{
		bzero(buf,255);
		do
		{
			ret = read(newfd,buf,255 - 1);
			}while(ret < 0 && errno != EINTR);
		if(ret < 0)
		{	
			perror("read");
			exit(1);
		}
		if(!ret)  //对方以关闭
		{
			break;
		}
		printf("Receive data :%s\n",buf);
		if(!strncasecmp(buf,"quit",4))
		{
			break;
		}
	}
	close(newfd);
	close(fd);
	return 0;
}

client端简单示例代码

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

int main(int argc, const char *argv[])
{
	int fd = -1;
	struct sockaddr_in sin;
	int ret ;
	/*1.创建socket套接子*/
	if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("socket");
		exit(1);
	}
  	/*2.链接服务器*/
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(5001);
	sin.sin_addr.s_addr = inet_addr("192.168.1.3"); /*只适用于IPV4*/
	/*inet_pton(AF_INET,"127.0.0.1",(void *)&sin.sin_addr.s_addr);*/
	/*最后进行发送连接请求*/
	if(connect(fd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		perror("connect");
		exit(1);
	}
 	
	/*3.读写*/
	ret = -1;
	char buf[255];
	while(1)
	{
		bzero(buf,255);
		if(fgets(buf,256,stdin) == NULL)
		{
			continue;
		}
		ret = write(fd,buf,strlen(buf));
		if(!strncasecmp(buf,"quit",4))
		{
			break;
		}
	}
	/*关闭套接字*/
	close(fd);
	return 0;
}

存在的问题

????????在服务端read函数处是具有一个阻塞功能,当一个客户端连接服务器,服务器进行读的处理,程序一直阻塞在read处,如果又有一个客户端请求连接服务器,这时的服务器accept函数没有执行,所以不能连接心的客户端。这就意味着不能实现并发。改进方法,可以使用多线程,多进程编程等方法解决。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-07-13 17:51:11  更:2021-07-13 17:53:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 13:57:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计