linux&C这两天学到了网络编程这一章,自己写了一个小的”服务器”和”客户端”程序,目的在于简单理解tcp/ip模型,以及要搭建一台简单服务器,服务器和客户端最基本的事情要干什么,这篇博客就这个小程序,也简单分析了自己对”TCP-三次握手”过程的理解。因为初学网络编程,说的不对的地方欢迎大家评论交流。

套接字:
套接字由4部分组成,服务器IP地址和客户端IP地址以及服务器端口号和客户端端口号,是客户端和服务器端传输数据确定线路的保证,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

首先我们来看服务器端的代码:

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h> #define MAX_QUEUE_LENGTH 1024 int main(int argc,char *argv[])
{
int sock_fd,conn_fd;
struct sockaddr_in serv_addr,conn_addr;
socklen_t conn_len;
pid_t pid1;
char recv_buf[128];
int ret; //创建套接字
sock_fd = socket(AF_INET,SOCK_STREAM,0);
/*参数分别为(使用IPV4 tcp/ip协议,使用tcp流套接字,
通过前两个参数来确定使用的协议类型,默认为零)*/ //mZ服务器端的套接字进行初始化
memset(&serv_addr,0,sizeof(struct sockaddr_in));
//memset函数将serv_addr 用0进行初始化
serv_addr.sin_family = AF_INET;
/*设置地址类型:对于sin_family,表示用tcp/ip协议编程,
所以此值只能为AF_INEF*/
serv_addr.sin_port = htons(4507);
//设置端口号为4507
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//关于ANADDR——ANY这个宏的解释在下面有,也可以向下面一样设定指定IP
//inet_pton(AF_INET,"XXX.XXX.XXX.XXX",&serv_addr.sin_addr);
//当我只有一块网卡,一个IP,所以也只能设置为自己的ip了 //绑定套接字
bind(sock_fd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr_in));
/*绑定套接字的过程是将我前面创建的套接字与初始化的端口绑定起来, 因为socket只是创建了一个套接字,这个套接字将在哪个端口上工作, 并没有被指定,作为服务器,它的IP和端口一般是固定的,因此我们需要将刚才
初始化的端口和套接字绑定到一起,这时套接字已经完成服务器的ip和端口这一半*/ //将套接字转化成监听套接字
listen(sock_fd,MAX_QUEUE_LENGTH);
//第二个参数比较重要,它是我们服务器已完成套接字队列的长度,accept函数每次
//会从已完成的套接字队列中拿走一个即conn_fd,也就是监听套接字,注意:内核会维护两个队列,
//一个是已完成的套接字队列,一个是未完成的套接字队列,一个套接字完成的过程是在三次握手的
//过程中完成的,是由tcp/ip协议栈完成的 //接受客户端的请求
conn_len = sizeof(struct sockaddr_in);
while(1)
{
conn_fd = accept(sock_fd,(struct sockaddr *)&conn_addr,&conn_len);
//服务器会将客户端的连接消息先放在未完成的队列中,三次握手之后,就到已完成队列中
//conn_fd就是accept返回的叫作连接套接字,它的信息有服务器的端口和IP以及客户的端口和IP,
//监听套接字继续监听,对于新的处理,系统会重新开一个线程处理,自己也可以用进程
printf("accept a new connection,ip:%s\n",inet_ntoa(conn_addr.sin_addr));
pid1 = fork();
if(pid1 == 0)
ret = recv(conn_fd,recv_buf,sizeof(recv_buf),0);
recv_buf[ret-1] = '\0';
}
printf("%s\n",recv_buf);
}

注释中解释了套接字的初始化,建立,绑定,监听的过程,结束之后我们服务器端的工作就做好了,为了检验程序是否正确,运行程序之后我们可以用netstat命令查看我们服务器端是否开启监听模式

$ netstat -apt | grep LISTEN


可以看到4507端口的状态是LISTEN。

在说说INADDR_ANY的作用

INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。举个例子:你的电脑上如果有多块网卡就会有好几个IP,或者说你的服务器有多台主机也会有好多个IP,而如果你的IP会发生变化,比如变多或者变少,但是为了减少bind()时的麻烦,可以统一设定就在0.0.0.0这个地址上监听。所有的信息都会到这个地址上,如果你需要将服务器上的所有IP中的80端口监听,再将80端口绑定就OK了,我就了解了这么多。

然后再看我们的客户端代码:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<netinet/in.h> int main(int argc,char *argv)
{
struct sockaddr_in serv_addr;
int conn_fd; //同样我们需要在客户端也建立套接字
conn_fd = socket(AF_INET,SOCK_STREAM,0); //初始化与服务器端匹配的信息
memset(&serv_addr,0,sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(4507);
inet_aton("192.168.20.144",&serv_addr.sin_addr); //用于向服务器端发送连接请求,服务器的IP地址和端口号由参数serv_addr指定
connect(conn_fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in));
close(conn_fd);
}

客户端有点简单啊,但是可以登录,这样就可以基本实现我们的客户端和服务器之间连接了,下面我们进入我们的主题:是不是都忘了我们的主题是——“三次握手“。
在这个实例中,三次握手发生在客户端执行connect函数的时候。三次握手的过程下面的图片可以显示清楚,我再举个例子

第一次 client->server SYN=1,seq = x
第二次 server->client SYN=1,ACK = 1,seq = y,ack = x+1
第三次 client->server ACK=1,seq = x+1
SYN:同步序号,当SYN=1,ACK=0时,表明这是一个连接请求。
ACK:当ACK=1时,确认号字段即ack才有效。
seq:范围:[0,2^32 - 1],表示发送的第一个字节的编号。
ack:确认号,当ack = n,表示到n-1为止的所有字节都已经被收到。

另外我用tcpdump命令抓了个包,可以分析下,不对的地方指出

$ tcpdump port 4507


我的客户端IP为192.168.122.172,服务器的IP为192.168.20.128
第一次:Flag[S],表示这是一个请求连接,S是SYN字母的首字母,seq是将要发送的首字节的序列号,此时SYN = 1,ACK = 0。
第二次:收到SYN = 1的包,将ACK置为1,ack = 1588197944表示在此之前的字节我已经全部收到。
第三次:当再次收到SYN=1,ACK=1的包时,将ack = 1,表示确认连接。

“TCP:三次握手”分析——以一个简单的“服务器”和“客户端”为例的更多相关文章

  1. Wireshark抓包介绍和TCP三次握手分析

    wireshark介绍 wireshark的官方下载网站: http://www.wireshark.org/ wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示 ...

  2. TCP三次握手四次分手—简单详解

    关于TCP三次握手四次分手,之前看资料解释的都很笼统,很多地方都不是很明白,所以很难记,前几天看的一个博客豁然开朗,可惜现在找不到了.现在把之前的疑惑总结起来,方便一下大家. 疑问一,上图传递过程中出 ...

  3. 用C++写一个简单的服务器和客户端

    我们将创建一个服务器节点add_two_ints_server,它将会收到两个整数,并且返回它们的和.切换目录到之前建立的beginner_tutorials包下: cd ~/catkin_ws/sr ...

  4. 抓包工具-Wireshark(详细介绍与TCP三次握手数据分析)

    功能使用的详细介绍 wireshark(官方下载网站: http://www.wireshark.org/),是用来获取网络数据封包,可以截取各种网络封包,显示网络封包的详细信息,包括http,TCP ...

  5. Wireshark抓包TCP三次握手数据

    抓包工具 - Wireshark(详细介绍与TCP三次握手数据分析) 功能使用的详细介绍 wireshark(官方下载网站: http://www.wireshark.org/),是用来获取网络数据封 ...

  6. 这次一定让你记住 TCP 三次握手、四手挥手!

    TCP协议全称为:Transmission Control Protocol,是一种面向链接.保证数据传输安全.可靠的数据传输协议.为了确保数据的可靠传输,不仅需要对发出的每个字节进行编号确认,还需要 ...

  7. 详解TCP三次握手(建立TCP连接过程)

    在讲述TCP三次握手,即建立TCP连接的过程之前,需要先介绍一下TCP协议的包结构. 这里只对涉及到三次握手过程的字段做解释 (1) 序号(Sequence number) 我们通过 TCP 协议将数 ...

  8. 简单说说TCP三次握手、四次挥手机制

    1.什么是TCP TCP全称Transmission Control Protocol(传输控制协议),是一种面向连接的.可靠的.基于字节流的传输层通信协议.是为了在不可靠的互联网络上提供可靠的端到端 ...

  9. 用tcpdump分析tcp三次握手,四次挥手

    1.tcpdump 简介 tcpdump是一个对网络上的数据包进行截获的包分析工具,一般linux系统以命令的形式使用 2.tcp三次握手 建立一个tcp连接会发生下面三个过程: 1.服务器必须准备好 ...

随机推荐

  1. animate.css VUE 使用

    1.安装 npm i animate.css --save 2.引用 main.jsimport 'animate.css' 3.使用 <img v-show="welcomeinde ...

  2. re.findall用法

    其中,re.findall() 函数可以遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表. 在python源代码中,展示如下: 搜索string,返回一个顺序访问每一个匹配结果(Match对象 ...

  3. 踩坑系列《五》 Incorrect datetime value: 时间添加失败原因

    在进行单元测试中通过 new Date() 方式添加时间时,报了 Data truncation: Incorrect datetime value:这样的错误(我数据库表的时间类型是 datetim ...

  4. LuoguP1557 Kruscal的加法 题解

    题目Link 就是这道题,做了我整整一天! 看到题目,首先想到的就是:就这?就这一道大水题也能是绿?然后十分钟写完代码,提交-- 果不其然,绿题不是白绿的,看了一眼数据和讨论,又得写高精了-- 先附上 ...

  5. The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved.Please check your configuration file.... 检查一下 ...

  6. 解决npm : 无法加载文件 D:\Code\renren-fast-vue\node_modules\.bin\npm.ps1,因为在......

    解决这个问题: 看看错误信息: npm : 无法加载文件 D:\DevPath\nodejs\npm.ps1,因为在此系统上禁止运行脚本.有关详细信息,请参阅 https:/go.microsoft. ...

  7. PAT (Basic Level) Practice (中文)1031 查验身份证 (15分)

    1031 查验身份证 (15分) 一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为: {7,9,10,5,8,4,2 ...

  8. Golang通脉之基础入门

    为什么要学 Go 性能优越感:Go 极其地快,其性能与 Java 或 C++相似.在使用中,Go 一般比 Python 要快 30 倍: 序列化/去序列化.排序和聚合中表现优异: 开发者效率较高:多种 ...

  9. 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链

    散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...

  10. Egg.js学习与实战系列 · 文件上传配置

    在使用Egg.js搭建文件上传服务时,遇到了几个一般新手都会遇到的坑. 经查阅官方文档,Egg框架中默认使用egg-multipart插件进行文件上传,所以上传文件前需要做相关的配置. 上传文件提示: ...