套接字通信的客户端和服务端的实现

知识了解:

1.IP:本质是一个整型数,用于表示计算机在网络中的地址。IP协议版本有两个:IPv4和IPv6

IPv4(Internet Protocol version4):

  1. 使用一个32位的整型数描述一个IP地址,4个字节,int型
  2. 也可以使用一个点分十进制字符串描述这个IP地址: 192.168.247.135
  3. 分成了4份,每份1字节,8bit(char),最大值为255
    1. 0.0.0.0 是最小的IP地址
    2. 255.255.255.255是最大的IP地址
  4. 按照IPv4协议计算,可以使用的IP地址共有2^32个

IPv6(Internet Protocol version6):

  1. 使用一个128位的整型数描述一个IP地址,16个字节
  2. 也可以使用一个字符串描述这个IP地址: 2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b
  3. 分成了8份,每份2字节,每一部分以16进制的方式表示
  4. 按照IPv6协议计算,可以使用的IP地址共有2^18个数

2.端口

端口的作用是定位到主机上的某一个进程,通过这个端口进程就可以接收到对应的数据了。

比如:在电脑上运行了微信和QQ,小明通过客户端给我的微信发消息,电脑上的微信就收到了消息,为什么?

  1. 运行在电脑上的微信和QQ都绑定了不同的端口
  2. 通过IP地址可以定位到某一台主机,通过端口就可以定位到主机上的某一个进程
  3. 通过指定的IP和端口,发送数据的时候对端就能接收到数据了

端口也是一个整形数,unsigned short,一个16位整型数,有效端口的取值范围是:0~65535(0~2^16-1)

提问:计算机中所有的进程都需要关联一个端口吗?一个端口可以被重复使用吗?

  1. 不需要,如果这个进程不需要网络通信,那么这个进程就不需要绑定端口的
  2. 一个端口只能给某一个进程使用,多个进程不能同时使用同一个端口

3. 字节序转换函数

当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误的解释之。解决问题的方法是:发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端知道对方传送过来的数据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换(小端机转换,大端机不转换)。

网络字节顺序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而 可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用大端排序方式。

BSD Socket提供了封装好的转换接口,方便程序员使用。包括从主机字节序到网络字节序的转换函数: htons、htonl;从网络字节序到主机字节序的转换函数:ntohs、ntohl。

h - host 主机,主机字节序
to - 转换成什么
n - network 网络字节序
s - short unsigned short
l - long unsigned int

#include <arpa/inet.h>
// 转换端口
uint16_t htons(uint16_t hostshort); // 主机字节序 - 网络字节序
uint16_t ntohs(uint16_t netshort); // 网络字节序 - 主机字节序
// 转IP
uint32_t htonl(uint32_t hostlong); // 主机字节序 - 网络字节序
uint32_t ntohl(uint32_t netlong); //  网络字节序 - 主机字节序

4.socket 地址

socket地址其实是一个结构体,封装端口号和IP等信息。后面的socket相关的api中需要使用到这个socket地址。客户端 -> 服务器(IP, Port)

5. IP地址转换(字符串ip-整数 ,主机、网络 字节序的转换)

#include <arpa/inet.h>
// p:点分十进制的IP字符串,n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);
    af:地址族: AF_INET AF_INET6
    src:需要转换的点分十进制的IP字符串
    dst:转换后的结果保存在这个里面
 
// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
    af:地址族: AF_INET AF_INET6
    src: 要转换的ip的整数的地址
    dst: 转换成IP地址字符串保存的地方
    size:第三个参数的大小(数组的大小)
    返回值:返回转换后的数据的地址(字符串),和 dst 是一样的

6. TCP通信流程

// TCP 通信的流程
// 服务器端 (被动接受连接的角色)
1. 创建一个用于监听的套接字
    - 监听:监听有客户端的连接
    - 套接字:这个套接字其实就是一个文件描述符
2. 将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息)
    - 客户端连接服务器的时候使用的就是这个IP和端口
3. 设置监听,监听的fd开始工作
4. 阻塞等待,当有客户端发起连接,解除阻塞,接受客户端的连接,会得到一个和客户端通信的套接字
(fd)
5. 通信
    - 接收数据
    - 发送数据
6. 通信结束,断开连接


// 客户端
1. 创建一个用于通信的套接字(fd)
2. 连接服务器,需要指定连接的服务器的 IP 和 端口
3. 连接成功了,客户端可以直接和服务器通信
    - 接收数据
    - 发送数据
4. 通信结束,断开连接

7.套接字通信的服务器端实现

server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main() {
    // 1.创建监听的套接字
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1) {
        perror("socket");
        return -1;
    }

    // 2.绑定本地的IP port
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY; // 0 = 0.0.0.0 对于0来说,大端和小端是没有区别的的,因此不需要转换
    saddr.sin_port = htons(9999);//主机字节序转换成网络字节序
    
    int ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1) {
        perror("bind");
        return -1;
    }

    // 3.设置监听
    ret = listen(fd,128);
    if(ret == -1) {
        perror("listen");
        return -1;
    }

    // 4.阻塞并等待客户端的连接
    struct sockaddr_in caddr;
    int addrlen = sizeof(caddr);
    int cfd = accept(fd,(struct sockaddr*)&caddr,&addrlen);
    if(cfd == -1) {
        perror("accept");
        return -1;
    }

    // 连接建立成功,打印客户端的IP和端口信息
    char ip[32];
    
    printf("客户端的IP: %s,端口: %d\n",
            inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),
            ntohs(caddr.sin_port));
    
    // 5.通信
    while(1) {
        // 接收数据
        char buff[1024];
        int len = recv(cfd,buff,sizeof(buff),0);
        if(len > 0) {
            printf("client say: %s\n",buff);
            send(cfd,buff,len,0);
        }else if(len == 0) {
            printf("客户端已经断开了连接...\n");
            break;
        }else{
            perror("recv");
            break;
        }
    }
    
    // 关掉文件描述符
    close(fd);
    close(cfd);
    return 0;
}

8.套接字通信的客户端实现

client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main() {
    // 1.创建套接字
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1) {
        perror("socket");
        return -1;
    }

    // 2.连接服务器IP port
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    inet_pton(AF_INET,"192.168.88.129",&saddr.sin_addr.s_addr);
    int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1) {
        perror("connect");
        return -1;
    }

    int number = 0;
    // 3.通信
    while(1) {
        // 发送数据
        char buff[1024];
        sprintf(buff,"你好,呵呵哒,%d...\n",number++);
        send(fd,buff,strlen(buff) + 1,0);

        //接收数据
        memset(buff,0,sizeof(buff));
        int len = recv(fd,buff,sizeof(buff),0);
        if(len > 0) {
            printf("server say: %s\n",buff);
        }else if(len == 0) {
            printf("服务器已经断开了连接...\n");
            break;
        }else{
            perror("recv");
        }
        sleep(1);
    }
    // 关闭文件描述符
    close(fd);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ETM是Early Teaching Management System的简写,意为早教管理系统。 ETM V2012是针对目前全球市场各类早教中心、各大国际早教连锁机构,根据其管理和教学的特点,而专业研发的一套适合各类早教机构的大型综合类一体信息化全能解决方案管理系统。 【ETM思未早教管理系统2012产品特色产品功能】   01.手机短信、彩信收发模块   采用三大通信运营商直联通道,与系统融合,支持各类手机短信、彩信的单发、群发、即时和定时发送,支持超长短信,支持短信模板自定义发送。   02.邮件收发模块   产品支持各类邮箱的SMTP、IMAP等配置接收和发送,自定义模板和信纸等功能。   03.内部通知收发模块   产品支持公司内部各类别各类型的通知接收、发送、查阅、个性化图片、文字、视频混合排版和管理等功能。   04.CRM管理模块   产品支持客户信息智能维系、管理、跟踪、预约、客户多次分配、会员报课、会员卡签到、刷卡、上课、请假、升班等流水一体化作业等子模块。   05.活动管理模块   产品支持不同类别不同时段的各类活动制定、分配、历史查阅,支持各类活动的排课、预约、签到等管理功能。   06.智能排课管理模块   产品支持各类课程包、课程、课时、节次的分类管理,支持智能与人工双重排课,支持按天、周、月等任选时间段排课,支持课表复制、查阅、划课计划等子模块。   07.合同管理模块   产品支持合同分类、关联课程包、课时、会员卡等,支持合同修改、存档、签约、到期、作废、终止等,支持退费、赠送等管理子模块。   08.企业架构管理模块   产品支持企业架构的各类冗繁自定义和权限分配,满足行业内各种多变复杂的架构环境与优化。   09.会员卡管理模块   产品支持IC卡、ID卡、磁条卡、FID卡等各类会员卡的使用,支持会员卡级别、分类管理,会员卡充值绑定、上课签到刷卡、活动刷卡、购买刷卡等,支持卡的升级、挂失、冻结、密码重置、查询等管理子模块。   10.商品进销存管理模块   产品支持商品的采购系列、供应链管理、定价、各类促销、优惠策略,支持系统刷卡消费、购买、租用商品,支持商品的各类数据统计、汇总等子模块。   11.统计报表模块   产品支持市场、销售、教学、客服等各类统计报表的自定义组装、二次开发,支持各类图形立体报表、各类数字报表,报表数据分析、历史报表、即时报表的查询、导出等功能。   12.任务提醒模块   产品支持秘书台服务,可根据流程作业,各类新赠任务、未完成任务跟踪、提醒、生日、预约到访、体验、活动、合同、上课情况等的分时分段预报功能,是您工作的真正小助手。   13.数据管理模块   产品支持数据库的即时同步备份、自动备份、异地备份等多种组合备份方式,同时数据采用认证和复杂的加密算法,保证数据的安全无忧。   14.角色权限管理模块   产品支持自定义角色和权限,详尽的权限规划,灵活的分配机制,可应付复杂多变的架构管理与人事变动调整。   15.栏目菜单管理模块   产品支持每个子菜单的位置和区域的动态调整、修改、删除、排列等,使您可自由定制真正属于自身企业风格的个性化产品。   16.操作日志管理模块   产品支持记录每一位操作人员在任何时间任何地点的详细操作记录,方便事务的跟踪处理和责任排查,使您对公司所有操作人员的工作情况了如指掌。 ETM V2012采用服务端C/S安全稳定的云集群设计,客户端采用B/S自由灵活访问,在授权许可下,使您无论在公司、外出或家中的任何时间、任何连接internet地方,都可轻松自由的处理工作、监管进度,合理利用每一分时间,提升工作效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

呵呵哒( ̄▽ ̄)"

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

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

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

打赏作者

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

抵扣说明:

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

余额充值