c++网络编程

网络编程模型

    c/s 模型:客户端服务器模型

    b/s 模型:浏览器服务器模型

1.tcp网络流程

在这里插入图片描述
服务器流程:

    1.创建套接字

    2.完善服务器网络信息结构体

    3.绑定服务器网络信息结构体

    4.让服务器处于监听状态

    5.accept阻塞等待客户端连接信号

    6.收发数据

    7.关闭套接字

客户端流程:

    1.创建套接字

    2.连接connect

    3.收发数据

    4.关闭套接字

2.函数

2.1socket

#include <sys/types.h>          
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
功能:创建套接字

参数:domain:通信域

                    Name                                 Purpose                                                Man page
                    AF_UNIX,AF_LOCAL          Local communication(本地通信)          unix(7)
                    AF_INET                             IPv4 Internet protocols                         ip(7)
                    AF_INET6                           IPv6 Internet protocols                         ipv6(7)
                    AF_PACKET                        原始套接字                                          packet(7)

             type:套接字的类型

                        SOCK_STREAM            TCP

                        SOCK_DGRAM              UDP使用

                        SOCK_RAW                    原始套接字使用

              protocol:附加文件,没有写0

返回值:成功:创建的新套接字(文件描述符)

              失败:-1  重置错误码

2.2bind

#include <sys/types.h>          
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定套接字和网络信息结构体

参数:sockfd:socket函数产生的套接字文件描述符(socket函数返回值)

                      addr:避免冲突警告

2.3listen

#include <sys/types.h>          
#include <sys/socket.h>

int listen(int sockfd, int backlog);产生半连接队列

功能:将套接字设置成被动监听状态,只有这个状态的套接字才能等待客户端连接

参数:sockfd:socket函数返回值

           backlog:半连接队列的长度,一般传 5 10 都行 不是0就行

返回值:成功:0

              失败:-1  重置错误码

accept

#include <sys/types.h>          
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);产生全连接队列,返回值创                                                                                                        建的文件描述符
功能:提取半连接队列中的第一个客户端连接,成功,放到函数产生的全连接队列中,专门             用于和当前客户端通信,返回的套接字和原套接字类型相同

参数:sockfd:listen后的sockfd

           addr:客户端的网络信息结构体首地址,不关心写NULL

           addrlen:客户端addr长度,不关心写NULL

返回值:成功:创建的新的文件描述符  专门用于和当前客户端通信

              失败:-1  重置错误码

connect

#include <sys/types.h>          
#include <sys/socket.h>

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

功能:与服务器建立连接 

参数:sockfd:accept函数返回值

          addr:服务器的网络信息结构体

          addrlen:addr的长度

返回值:成功:0

              失败:-1  重置错误码

服务器代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#define ERRLOG(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        perror(msg);\
        exit(-1);\
    }while(0)
 
 
int main(int argc, char const *argv[])
{
    //1.创建套接字
    int sockfd=0;//需要接函数返回值,后面函数会用
    if(-1==(sockfd=socket(AF_INET,SOCK_STREAM,0))){
        ERRLOG("socket error");
    }
    
    //2.服务器网络信息结构体填充
    //struct sockaddr addr;
    struct sockaddr_in ad;
    memset(&ad, 0, sizeof(ad));
    ad.sin_family=AF_INET;
    ad.sin_port=htons(7788);//自己随意指定,不冲突就行,冲突就换
    ad.sin_addr.s_addr=inet_addr("192.168.250.100");
   
    //3.绑定套接字和服务器网络信息结构体
    if(-1==bind(sockfd,(struct sockaddr*)&ad,sizeof(ad))){
        ERRLOG("bind error");
    }
 
    //4.让套接字处于被动监听状态
    if(-1==listen(sockfd,5)){
        ERRLOG("listen error");
    }
    
 
    //5.阻塞等待客户端连接
    printf("正在等待客户端发来信息\n");
    int newfd=0;
    if((newfd=accept(sockfd,NULL,NULL))==-1){
        ERRLOG("accept error");
    }
    printf("客户端连接成功\n");
 
    //6.收发数据
    char buff[128]={0};
    int lnum=0;
    char opr=0;
    int rnum=0;
    int result=0;
    read(newfd,buff,128);
    printf("客户端发来数据:%s\n",buff);
    sscanf(buff,"%d%c%d",&lnum,&opr,&rnum);
    switch(opr){
        case '+':
            result=lnum+rnum;
            break;
        case '-':
            result=lnum-rnum;
            break;
        case '*':
            result=lnum*rnum;
            break;
        case '/':
            result=(float)lnum/(float)rnum;
            break;
    }
    memset(buff,0,128);
    sprintf(buff,"result=%d",result);
    write(newfd,buff,128);
 
    //7.关闭套接字
    close(sockfd);
    close(newfd);
    return 0;
}

客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
 
#define ERRLOG(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        perror(msg);\
        exit(-1);\
    }while(0)
 
int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd=0;
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
        ERRLOG("socket error");
    }
 
    //填充服务器结构体
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(6666);
    addr.sin_addr.s_addr=inet_addr("192.168.2.84");
    
    //连接服务器
    if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr))==-1){
        ERRLOG("connect error");
    }
 
    //收发数据
    char buff[128]={0};
    //写入的数据从终端获取
    fgets(buff,128,stdin);
    buff[strlen(buff)-1]='\0';
    write(sockfd,buff,128);
 
    memset(buff,0,128);
    read(sockfd,buff,128);
    printf("服务器发来的信息是:%s\n",buff);
    
    //7.关闭套接字
    close(sockfd);
    return 0;
}

send

#include <sys/types.h>          
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

功能:发送数据

参数:sockfd:accept函数返回值

           buf:要发送的数据的缓冲区首地址

           len:要发送数据的长度

           flags:发送的标志位,0用法和write就一样了,MSG_DONTWAIT 表示非阻塞

返回值:成功:实际发送的字节数

              失败:-1  重置错误码

注意:

            如果对方关闭了套接字或者断开连接

            第一次send没有反应,第二次send会产生SIGPIPE信号

下面三种用法是等价的:

                write(sockfd, buf, 128);

                send(sockfd, buf, 128, 0);

                sendto(sockfd, buf, 128, 0, NULL, NULL);

recv

#include <sys/types.h>          
#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                            struct sockaddr *src_addr, socklen_t *addrlen);

功能:接收数据 

参数:

           sockfd:accept函数返回值

           buf:要接收的数据的缓冲区首地址

           len:要接收数据的长度

           flags:发送的标志位,flags:接收的标志位,0用法和read就一样了,                                                   MSG_DONTWAIT 表示非阻塞

返回值:成功:实际接收的字节数

              失败:-1  重置错误码

注意: 如果对方关闭了套接字或者断开连接 recv 会返回0

下面三种用法是等价的:

         read(sockfd, buf, 128);

         recv(sockfd, buf, 128, 0);

         recvfrom(sockfd, buf, 128, 0, NULL, NULL);

粘包问题产生原因

tcp在传输的时候不是一调用send就直接将数据发送给客户端的,而是将数据放到发送缓冲区里

tcp底层的nagle算法,会将一定短时间内发送的数据包组装成一个整体,发送给对方

而接受方无法区分消息的边界和类型,就可能会导致有冲突的情况发生

也就是说,当文件只剩最后一部分的时候,很有可能将最后的结束字符和文件最后一部分作为一个整体发送给接收方,也有可能将三个128和最后的30+12一起发给接收方,但不管是哪种方式,接收方写入的时候是以128为单位接受的,所以接收方缓冲区里是无法单独比较over的,所以会产生粘包问题。

解决方法:

1.既然是一定短时间内的数据成为一个整体,那么最后发送的over就不和前面一块发送了,在over之前加一个延时函数,让他单独发送

但是不常用,因为服务器里禁止使用sleep

2.发送定长的数据包,

解决方法一代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/48011.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用EasyPoi实现Excel的按模板样式导出

模板文件 1690342020350导出测试.xlsx 导出文件 如下 1&#xff0c;横向遍历 #fe 使用#fe命令可以实现集合数据的横向拓展&#xff0c;比如模板代码是 {{#fe:maths t.score}}导出的excel里面就会显示会自当前列&#xff0c;向右拓展&#xff0c;效果可参见下面的导出文件…

Retrospectives on the Embodied AI Workshop(嵌入式人工智能研讨会回顾) 论文阅读

论文信息 题目&#xff1a;Retrospectives on the Embodied AI Workshop 作者&#xff1a;Matt Deitke, Dhruv Batra, Yonatan Bisk 来源&#xff1a;arXiv 论文地址&#xff1a;https://arxiv.org/pdf/2210.06849 Abstract 我们的分析重点关注 CVPR Embodied AI Workshop 上…

【LeetCode】114.二叉树展开为链表

题目 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。 示例 1&…

紫光FPGA试用--软件篇

目录 一 软件安装启动 二 如何打开IP核&#xff1f;查看/修改现有IP核参数&#xff1f; 三 如何定义引脚&#xff1f; 四 如何下载code进入FPGA? 1. 下载到FPGA芯片内&#xff1a; 2.下载到外部FLASH中 五 如何进入在线调试模式&#xff0c;调试步骤 操作步骤&#xff…

Stack

文章目录 定义分类静态栈动态栈 算法应用 定义 在静态内存当中分配的叫做栈&#xff0c;在动态内存中分配的叫做堆。 **红色椭圆圈当中的就是在栈中分配的&#xff0c;蓝色下划线的就是在堆里分配的。**栈和堆表示的是分配数据的一种方式。静态局部变量是通过压栈和出栈来分配…

Sentinel针对IP限流

改造限流策略的针对来源选项 import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class Senti…

每日一题——除自身以外数组的乘积

除自身以外数组的乘积 题目链接 这一题乍一看好像十分简单&#xff0c;先用一趟循环遍历所有数据&#xff0c;得到数据所有元素的乘积&#xff0c;再用一趟循环将这个乘积除以每个元素&#xff0c;这样不就得到了除自身以外数组的乘积吗&#xff1f;我们先来看看代码&#xff…

【iOS】isKindOfClass和isMemberOfClass方法

前言 这个归根结底还是在考察我们对isa走向图和类的继承的理解&#xff0c;也就是苹果官方这幅图&#xff1a; 接下来的函数调用流程请参考这张图。 1 isKindOfClass方法 1.1 objc_opt_isKindOfClass C函数 查看源码可发现&#xff0c;无论是谁调用isKindOfClass方法都会…

了解Unity编辑器之组件篇Event(七)

Event&#xff1a;用于在对象之间进行通信和交互的机制。它可以帮助你实现触发和响应特定动作或状态的逻辑一、Event System&#xff1a;用于处理 UI 事件的系统组件 First Selected 属性&#xff1a;定义了在场景加载或 UI 激活时&#xff0c;哪个 UI 元素将成为首选的选中元素…

Kotlin多平台最佳架构指南

在这篇文章中&#xff0c;我们将对 Kotlin 多平台移动端的最佳架构进行深入探讨。在2023年&#xff0c;作为 Android 开发者&#xff0c;我们会倾向于采用 MVVM 架构&#xff0c;因为它简单、灵活且易于测试。而作为 iOS 开发者&#xff0c;我们可能会选择 MVC、Viper 等架构。…

win11安装appium

node安装 node下载网址: Download | Node.js 安装后对node安装包路径进行配置 npm config set prefix “E:\nodejs\node_global” //设置全局包目录 npm config set cache “E:\nodejs\node_cache” //设置缓存目录npm config list //查看npm配置npm install -g appium //安…

Windows SMB 共享文件夹 排错指南

1 排错可能 是否系统名称为全英文格式 如果不是则 重命名 根据如下排错可能依次设置 1&#xff0c;在运行里面输入"secpol.msc"来启动本地安全设置&#xff0c;\ 然后选择本地策略–>安全选项 -->网络安全LAN 管理器身份验证级别&#xff0c;\ “安全设置”…

C#实现数字验证码

开发环境&#xff1a;VS2019&#xff0c;.NET Core 3.1&#xff0c;ASP.NET Core API 1、建立一个验证码控制器 新建两个方法Create和Check&#xff0c;Create用于创建验证码&#xff0c;Check用于验证它是否有效。 声明一个静态类变量存放列表&#xff0c;列表中存放包含令…

如何维护你的电脑:提升性能和延长使用寿命

如何维护你的电脑&#xff1a;提升性能和延长使用寿命 &#x1f607;博主简介&#xff1a;我是一名正在攻读研究生学位的人工智能专业学生&#xff0c;我可以为计算机、人工智能相关本科生和研究生提供排忧解惑的服务。如果您有任何问题或困惑&#xff0c;欢迎随时来交流哦&…

【深度学习】从现代C++中的开始:卷积

一、说明 在上一个故事中&#xff0c;我们介绍了机器学习的一些最相关的编码方面&#xff0c;例如 functional 规划、矢量化和线性代数规划。 本文&#xff0c;让我们通过使用 2D 卷积实现实际编码深度学习模型来开始我们的道路。让我们开始吧。 二、关于本系列 我们将学习如何…

【Unity实用插件篇】| A* Pathfinding Project - A*寻路插件 的使用教程

前言【Unity实用插件篇】| A*寻路插件学习使用一、A*算法 简述二、A* Pathfinding Project 介绍2.1 A* Pathfinding Project 功能2.2 相关链接2.3 标准版和Pro版区别2.4 A* Pathfinding Project Free与Navigation的对比三、快速搭建一个自己的场景测试寻路3.1 寻路场景搭建3.2 …

python绘制3D条形图

文章目录 数据导入三维条形图bar3d 数据导入 尽管在matplotlib支持在一个坐标系中绘制多组条形图&#xff0c;效果如下 其中&#xff0c;蓝色表示中国&#xff0c;橘色表示美国&#xff0c;绿色表示欧盟。从这个图就可以非常直观地看出&#xff0c;三者自2018到2022年的GDP变化…

python使用CGI编程,网页写个标题

需要有个 Linux虚拟机&#xff0c;安装 apache&#xff0c; 本次使用 deepin v23&#xff0c;参考&#xff1a; sudo apt install apache2 #安装 apache2 systemctl start apache2 # 启动 apache2 sudo a2enmod cgi # 启用CGI模块 sudo mkdir /usr/lib/cgi-bin #创…

初识Mybatis,并创建第一个Mybatis项目(详细图文教程)

目录 前言 一、Mybatis是什么&#xff1f; 二、Mybatis的优点 三、创建第一个Mybatis项目 配置Mybatis开发环境 创建数据库 添加框架 配置连接字符串和Mybatis 使用Mybatis操作数据库 测试 前言 Spring 集成了 Mybatis 框架&#xff0c;方便我们更加便捷的使用&#…

关于自签名证书授权后在哪儿看

目录 firefox可以看到 chrome and edge firefox可以看到 chrome and edge 只能从打开的网站左上角进入