一个简单的聊天系统

声明:谢绝一切形式的转载

socket套接字

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现, socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭). 说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议
在这里插入图片描述

TCP/IP

TCP三次握手

tcp的三次握手如下所示。
在这里插入图片描述有很多面试官很特别容易问为什么两次不行?个人感觉,两次也不是不行。只是在有些情况下会产生无效的连接。
比如客户端发起连接,由于网络阻塞,服务器一直没有收到连接请求,客户端没有收到任何回应,启动重传机制,又发起了一次连接,这次很顺利,然后服务端正常返回信息,第二次的连接成功了。可是,万万没想到,那个阻塞的连接经过跋山涉水终于到了服务器端,此时服务器作何处理那
服务器端认为你咋又发了个请求呀,于是再次进行确认,客户端收到一条服务器端的一个确认,不予理会。可服务器却坚持认为连接已经成功,等待客户端传输数据,于是服务器的许多资源就浪费了。

抓包分析

个人认为,涉及到tcp/ip原理讲解的,空讲理论略显不足,甚至有点"耍流氓"的感觉。"三次握手,四次挥手"这种理论书本中讲述的很清楚了,下面以WireShark工具见证一下这个理论。

三次握手

在这里插入图片描述通过上面可以看出三次握手的流程

  1. 客户端向服务器端发送[SYN],seq=0
  2. 服务端向客户端返回[SYN,ACK] Ack=1 seq=0
  3. 客户端向服务器端返回[ACK] Ack=1
四次挥手

在这里插入图片描述在这里插入图片描述

tcp状态变迁图

在这里插入图片描述

基本的socket函数

使用socket编程用到的函数和基本流程如下:
在这里插入图片描述
注意:还有两个函数send和recieve。这两个函数比较容易望文生义,认为是send把数据发送出去。其实不是这样子的,只有当send把socket的发送缓冲区填满的时候数据才进行发送,通过TCP/IP协议进行发送。进行数据传输的是协议。

简单聊天系统

前面的理论知识还是很有必要了解的。之后开发程序就简单多了。先看以下效果:
在这里插入图片描述

服务器端代码

/*************************************************************************

 > File Name: ser.c

 > Author: 无情剑客

 > Mail: 2250911301@qq.com

 > Created Time: 2020年7月1日21时43分10秒
  ************************************************************************/

 #include<stdio.h>

 #include<stdlib.h>

 #include<string.h>

 #include<sys/types.h>

 #include<sys/socket.h>

 #include<unistd.h>

 #include<netinet/in.h>

 #include<arpa/inet.h>

 #define PORT 6666

 #define BACKLOG 10

 #define MAXDATASIZE  2048

int main(int argc, char *argv[])

{

    int listenfd;

    //创建一个socket描述符,此描述符仅是本主机上的一个普通文件描述符而已

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    //定义一个结构体变量servaddr,用来记录给定的IP和port信息,为bind函数做准备

    struct sockaddr_in serveraddr;

    bzero(&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(PORT); //把端口转化为网络字节序,即大端模式

    serveraddr.sin_addr.s_addr = INADDR_ANY;

    //把“本地含义的描述符”绑定到一个IP和Port上,此时这个socket才具备对外连接的能力

    bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));

    //创建一个监听队列,用来保存用户的请求连接信息(ip、port、protocol)

    listen(listenfd, BACKLOG);

    printf("======端口绑定成功,等待客户端的连接======\n");

    //让操作系统回填client的连接信息(ip、port、protocol)

    struct sockaddr_in peeraddr;

    socklen_t peer_len = sizeof(peeraddr);

    int connfd;

    while(1)

    {

        //accept函数从listen函数维护的监听队列里取一个客户连接请求处理

        connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peer_len);

        printf("\n=====================客户端链接成功=====================\n");

        printf("IP = %s:PORT = %d\n", inet_ntoa(peeraddr.sin_addr), 		ntohs(peeraddr.sin_port));

        char buf[MAXDATASIZE];

        while(1)

        {

            memset(buf, '\0', MAXDATASIZE/sizeof  (char));

            int recv_length = recv(connfd, buf, MAXDATASIZE/sizeof (char), 0);

            if(recv_length == 0)

            {

                printf("客户端已经关闭!\n");

                break;

            }
            char vul_buffer[64] ;
            strcpy(vul_buffer,buf);

            printf("客户端说: ");

            fputs(vul_buffer, stdout);

            memset(buf, '\0', MAXDATASIZE/sizeof (char));

            printf("请输入: ");

            fgets(buf, sizeof(buf), stdin);

            send(connfd, buf, recv_length, 0);

        }

        close(connfd);

        close(listenfd);

        return 0;

    }
}

这里使用了strcpy这个危险函数,后续文章会针对这个漏洞进行攻击。

客户端代码

/*************************************************************************

> File Name: client.c

> Author: 无情剑客

> Mail: 2250911301@qq.com

> Created Time: 2020年07月01日 星期三 21时44分37秒

 ************************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<unistd.h>

#include<netinet/in.h>

#define PORT 6666

#define MAXDATASIZE 2048

int main(int argc, char *argv[])

{

    if(argc != 2)

    {

        fprintf(stderr, "请您输入ip地址!\n");

        exit(1);

    }

    int sockfd;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    const char *server_ip = argv[1]; //从命令行获取输入的ip地址,此处没有对ip地址进行检验

    struct sockaddr_in serveraddr;

    bzero(&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(PORT);

    inet_pton(AF_INET, server_ip, &serveraddr.sin_addr);

    connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));

    printf("=====================服务器链接成功=====================\n");

    char buf[MAXDATASIZE];

    memset(buf, 0 ,  sizeof(buf));

    printf("请输入: ");

    while(fgets(buf, sizeof(buf), stdin) != NULL && (strcmp(buf, "quit")))

    {

        send(sockfd, buf, sizeof(buf), 0);

        memset(buf, 0, sizeof(buf));

        recv(sockfd, buf, sizeof(buf), 0);

        printf("服务器说: ");

        fputs(buf, stdout);

        memset(buf, 0, sizeof(buf));

        printf("请输入: ");

    }

    printf("客户端将要被关闭,下次再见\n");

    close(sockfd);

    return 0;

}

使用如下命令进行编译

gcc -o client client.c && gcc -o server  server.c 

公众号

更多网络安全,欢迎关注我的公众号:无情剑客
在这里插入图片描述

热门文章

暂无图片
编程学习 ·

吐血整理各种二叉树(BST、AVL、Red Black、B、B+)

前言 没有必要过度关注二叉树的增删改导致的结构改变,规则操作什么的了解一下就好,看不下去就跳过,本文过多的XX树操作图片纯粹是为了作为规则记录,该文章主要目的是增强下个人对各种常用XX树的设计及缘由的了解,也从中了解到常用的实现案例使用XX树实现的原因。 数据在计…
暂无图片
编程学习 ·

SQL Server—游标(是什么?声明、打开、检索、关闭、释放)

目录游标是什么?如何创建一个游标?操作游标的四个步骤?如何判断游标的提取状态?关闭游标就可以了为什么还要释放呢?他们有什么区别?游标是什么? 是一种数据访问机制,它允许用户单独的操作数据行,而不是对整个行集进行操作。用户可以通过单独处理每一行逐条手机信息并对…
暂无图片
编程学习 ·

Centos7下redis6.0.5的详细安装步骤

Centos7下redis6.0.5的详细安装步骤: 0、官网浏览,安装wget 1、打开 https://redis.io/download,浏览最新的redis信息。 2、安装wget:执行命令:yum install wget -y 备注:-y的意思是yes 1、wget获得redis安装包 执行: wget http://download.redis.io/releases/redis-6.0…
暂无图片
编程学习 ·

无线传输技术有哪些?

什么是ZigBee? ZigBee,也称紫蜂,是一种低速短距离传输的无线网上协议,底层是采用IEEE802.15.4标准规范的媒体访问层与物理层。主要特色有低速、低耗电、低成本、支持大量网上节点、支持多种网上拓扑、低复杂度、快速、可靠、安全。 三大特征、八大优势 特征一 ZigBee能源消…
暂无图片
编程学习 ·

Java语言基础之基础语法&流程控制语句&数组

Java语言概述 Java语言是一款面向对象的高级语言,是由Sun Microsystems公司(现已被oracle公司收购)。由James Gosling和同事们共同研发,并在1995年正式推出,据oracle官方数据指数,目前全球已有上亿的系统是使用Java开发的。Java是一门面向对象编程语言,不仅吸收了C++语言…
暂无图片
编程学习 ·

最长重复子数组(java)

问题描述: 给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。 样例: 代码见下: package Leetcode; import java.util.Scanner; public class FindLength {public static int findLength(int[] A, int[] B) {//暴力破解int len1=A.length;int len2=B.…
暂无图片
编程学习 ·

windows使用小技巧——Windows 10 HEVC扩展要收费怎么办?教你怎么免费下载HEVC扩展

平时我一般都使用potplayer打开视频,但在整理视频的时候mov格式的文件总是不能显示缩略图。如果用windows10自带图片查看器打开时会提示下载HEVC,点击后会要求付7元下载。本来已经准备支付宝了,结果发现要将支付宝账号加入windows账号下。。。算了算了,还是看看有没有别的办…
暂无图片
编程学习 ·

自定义注解,并通过注解进行数据库建表

1、自定义注解 1.1、这个注解用来指定表名 // An highlighted block package test.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(…
暂无图片
编程学习 ·

qt工程封装为dll库并调用

#.pro文件中加入如下语句,并注释掉原本相关原句在.h文件中的修改,将 xxx_global.h 文件中的内容拷贝到.h文件中,我们是直接修改pro文件的,所以这部分需要自己写入(没得给您复制噢)。形式如下,需要修改QDBLSIDERSHARED_EXPORT,将其修改为 xxx(工程名大写)SHARED_E…
暂无图片
编程学习 ·

SQL函数

SQL拥有很多可用于计数和计算的内建函数。SQL Aggregat函数计算从列中取得的值,返回一个单一的值。有用的Aggregate函数如下:AVG() - 返回平均值COUNT() - 返回行数FIRST() - 返回第一个记录的值LAST() - 返回最后一个记录的值MAX() - 返回最大值MIN() - 返回最小值SUM() - 返…
暂无图片
编程学习 ·

咸鱼软件应用—VMware下安装ubantu

咸鱼软件应用—VMware下安装ubantuubantu简介开源下载地址在VMware虚拟机安装ubantu系统 为了测试固件需要安装Linux系统,后面有测试说明。现在先把ubantu系统装上再说~ubantu简介 ubuntu基于linux的免费开源桌面PC操作系统,十分契合英特尔的超极本定位,支持x86、64位和ppc架…
暂无图片
编程学习 ·

python3 yield关键字简单使用

python3 yield关键字yield简单介绍如何改变文本的样式简单实例为什么需要生成器?实例优势 yield简单介绍 yield <==> 生成器 包含yield语句的函数是一个生成器 生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值 生成器是一个不断产生值的函数 如何…
暂无图片
编程学习 ·

通过小项目学习23种设计模式(四)

通过读取文件导入数据库功能学习23种设计模式 第一次重构代码 目前代码写的很随性,导致以后业务增加时拓展起来繁杂,所以我们将已有逻辑进行第一重构: 抽取公共的行为生成接口 package com.xiaoma.fileimport.common;/*** 任务主执行类* 使用工厂模式,首先将任务共同行为抽象出…
暂无图片
编程学习 ·

组合数学4-全排列与算法

文章目录全排列与算法一 钟声里的全排列**思考**:生成算法二 字典序法1.递归2.字典序法例1:生成字母abc的全排列例2:生成123的全排列例3:生成839647521的全排列3.**思考**:局部连续变化三 SJT算法(Steinhaus–Johnson–Trotter algorithm)1. 引出思路2. 可移动数(mobil…
暂无图片
编程学习 ·

6台路由器ospf+rip实验

一、环境OSPF路由协议是一种典型的链路状态(Link-state)的路由协议,一般用于同一个路由域内。在这里,路由域是指一个自治系统(Autonomous System),即AS,它是指一组通过统一的路由政策或路由协换路由信息的网络。在这个AS中,所有的OSPF路由器都维护一个相同的描述这个A…
暂无图片
编程学习 ·

Java之父 詹姆斯·高斯林 传奇的一生

Java之父 传奇的一生 Java之父 詹姆斯高斯林 詹姆斯高斯林 (James Gosling)是一名软件专家,1955年5月19日出生于加拿大,Java编程语言的共同创始人之一,一般公认他为“Java之父”。 1977年获得了加拿大卡尔加里大学计算机科学学士学位,1983年获得了美国卡内基梅隆大学计算…
暂无图片
编程学习 ·

疫情期间,注重鼻腔呼吸道清洁卫生,很重要

疫情期间清洁鼻腔很重要鼻子是人类呼吸道的门户,作为一个与外界直接相通的腔道,很像家里空调的风口,容易存留脏物。从生理结构上来看,鼻腔里有鼻毛和大量的黏膜褶皱,灰尘、微生物、病毒都可能积攒其中。所以,在“勤洗手、戴口罩”的非常时期,别忘了鼻腔的清洁工作。另据…
暂无图片
编程学习 ·

Python之闭包的学习

什么是闭包?内部函数对外部函数作用域内变量的引用,则内部函数称为闭包。闭包的条件:必须有内嵌函数(函数里面的函数)。内嵌函数必须引用一个定义在外部函数里面的变量。外部函数必须返回内嵌函数。 列子:def funcOut(a):def funcIn(b):return a + breturn funcInf = fun…
暂无图片
编程学习 ·

python学习笔记——持久化-文件

open 函数open 函数负责打开文件,带有很多参数 第一个参数:必须有,文件的路径和名称 mode:表明文件用什么方式打开r:以只读方式打开 w:写方式打开,会覆盖以前的内容 x:创建方式打开,如文件已经存在,报错 a:append 方式,以追加的方式对文件内容进行写入 b:binary 方…