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. javascript 求最大前5个数; 对象 深拷贝 deep copy

    * 用数组 function getTopN(a, n) { function _cloneArray(aa) { var n = aa.length, a = new Array(n); for ( ...

  2. Oracle基本入门

    一.数据的存储 1.java 程序中的对象:数组.集合保存.当运行的程序结束的时候,里面的数据就消亡. 2.文件存储系统: 存在的缺陷: 2.1)没有明确的数据类型划分. 2.2)没有用户身份验证机制 ...

  3. 使用亚马逊服务器报错:Signature not yet current: 20190726T070253Z is still later than 20190726T070246Z (20190726T065746Z + 15 min.)时间不同步的解决办法

    1.首先获取亚马逊的时间: $ curl http://s3.amazonaws.com -v 2.更改当前服务器时间,使之与亚马逊时间同步 $ date -s 'xxxx-xx-xx xx:xx:x ...

  4. Java安全之ClassLoader

    Java安全之ClassLoader 类加载机制 Java中的源码.java后缀文件会在运行前被编译成.class后缀文件,文件内的字节码的本质就是一个字节数组 ,它有特定的复杂的内部格式,Java类 ...

  5. USACO Section 4

    前言 好久没更新这个系列了,最近闲的无聊写一下.有两题搜索懒得写了. P2737 [USACO4.1]麦香牛块Beef McNuggets https://www.luogu.com.cn/probl ...

  6. kubelet源码分析——启动Pod

    前文说到Kubelet启动时,调用到kubelet.Run方法,里面最核心的就是调用到kubelet.syncLoop.它是一个循环,这个循环里面有若干个检查和同步操作,其中一个是地在监听Pod的增删 ...

  7. C#开发BIMFACE系列41 服务端API之模型对比

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在建筑施工图审查系统中,设计单位提交设计完成的模型/图纸,审查专家审查模型/图纸.审查过程中如果发现不符合规范的地方,则流 ...

  8. 洛谷3163 CQOI2014危桥 (最大流)

    一开始想了一发费用流做法然后直接出负环了 首先,比较显然的思路就是对于原图中没有限制的边,对应的流量就是\(inf\),如果是危桥,那么流量就应该是\(2\). 由于存在两个起始点,我们考虑直接\(s ...

  9. 数据库已经存在表, django使用inspectdb反向生成model实体类

    1.通过inspectdb处理类,可以将现有数据库里的一个或者多个.全部数据库表生成Django model实体类 python manage.py inspectdb --database defa ...

  10. Java(43)JDK新特性之方法引用

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228461.html 博客主页:https://www.cnblogs.com/testero ...