前言

  前面专题的例子都是基于应用层上的HTTP协议的介绍, 现在本专题来介绍下传输层协议——TCP协议,主要介绍下TCP协议的工作过程和基于TCP协议的一个简单的通信程序,下面就开始本专题的正文了。  

一、TCP的工作过程

  首先TCP是一种面向连接的,可靠的,基于字节流的传输层通信协议。TCP的工作过程可以分为三个阶段:一、连接的建立;  二、传输数据; 三、断开连接,下面就对这三个过程分别介绍下:

1.1 连接的建立

  TCP的连接建立就像打电话一样, 我们打电话时,拨一个号码的号码并不是立即就可以接通的,期间会有一个“嘟 嘟”的呼叫过程, 这就好比是TCP协议的连接的建立阶段。当我们用TCP编写的程序,必须先建立TCP连接。TCP协议的连接建立通过三次握手来完成的,下面是在网上找的一张TCP三次握手的图片:

            

下面就对这三次握手简单的介绍:

第一次握手:建立连接时,客户端发送SYN包(seq=x)到服务器,并进入SYN_Send状态,等待服务器确认

第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=x+1),同时自己也发送一个SYN包(SEQ=y),即SYN+ACK包,此时服务器进入SYN_Recv状态

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=y+1),此包发送完毕,客户端和服务器进入Established(建立)状态,完成三次握手。

简单理解三次握手就是发送一个检验包给对方然后互相确认,双方都接到确认的一个信号时,这时候双方就建立了连接(就像我们打电话时,如果没人说话时就会说下 “喂”,说这句“喂” 也就是希望得到对方的一个确认,虽然这里双方已经建立了连接的,这里只是更形象的说明下三次握手的过程)。

1.2 传输数据

  双方建立了连接,即在双方建立了一个通信通道(就像一座桥一样,在两端建立了一个通路,用桥来比喻通信通道主要是因为最近有一则新闻:哈尔滨阳明滩大桥坍塌事件),建立连接之后,当然是传输我们需要传输的数据到对方的,这里就开始简单介绍下传输数据的过程。

  利用TCP传输数据时,数据是以字节流的形式进行传输,客户端与服务器端建立连接后,发送方需要先将发送的数据转换为字节流,然后将其发送给对方,发送数据时,可以通过程序不断地将数据流陆续写入TCP的发送缓冲中,然后TCP自动从发送缓冲中提取一定量的数据,将其组成TCP报文段发送到IP层,再通过IP层(也就是网络层)之下的网络接口发送出去;接受端从IP层接收到TCP报文段后,将其暂时保存在接受缓冲中,然后我们通过程序依次读取接受缓冲中的数据,从而达到相互通信的目的(简单的说就发送方把数据转换为数据流,再把数据流存储在发送缓冲中,然后传输层低层的协议从发送缓冲中读取数据把数据发送出去,然后接收端从底层接受到数据把数据存储在接收端的缓冲中,然后我们写的程序只是从缓冲中依次读取数据,然后显示出来,在客户端我们写代码做的事情是把数据用Write方法写入发送端的缓冲中,然后服务器端(接收端)用Read方法在自己的缓冲中读取数据,用一句话概括,TCP的传输就是对数据的写——读操作)括号中的内容只是我个人理解,因为这样我感觉理解起来比较容易,对于刚开始接触TCP的朋友可以这样理解,然后再一句句话去扩展。  

1.3 断开连接

  发送完数据之后,最后就是断开连接了,下面是网上断开的连接的一张图片(断开一个连接需要经过四次握手):

  TCP的工作过程就分为上面三个过程,TCP编程是作为上层应用编程的基础,就像之前专题中基于HTTP协议的Web服务器,Web浏览器,其传输层都用的是TCP协议进行传输的,还有基于FTP(文件传输协议),IMAP(交互式邮件存取协议) POP3(邮局协议的第3个版本) 和SMTP(简单邮件传输协议)的网络应用其传输层都用的是TCP协议,而不是UDP等其他传输层协议。

二、基于TCP协议的简单通信程序

这里简单实现了一个客户端与服务器间的通信程序,核心代码为:

客户端连接服务器端代码:

 private void btnConnect_Click(object sender, EventArgs e)
{
// 通过一个线程发起请求,多线程
Thread connectThread = new Thread(ConnectToServer);
connectThread.Start();
} // 连接服务器方法,建立连接的过程
private void ConnectToServer()
{
try
{
// 调用委托
statusStripInfo.Invoke(showStatusCallBack, "正在连接...");
if (tbxserverIp.Text == string.Empty || tbxPort.Text == string.Empty)
{
MessageBox.Show("请先输入服务器的IP地址和端口号");
} IPAddress ipaddress = IPAddress.Parse(tbxserverIp.Text);
tcpClient = new TcpClient();
tcpClient.Connect(ipaddress, int.Parse(tbxPort.Text)); // 延时操作
Thread.Sleep();
if (tcpClient != null)
{
statusStripInfo.Invoke(showStatusCallBack, "连接成功");
networkStream = tcpClient.GetStream();
reader = new BinaryReader(networkStream);
writer =new BinaryWriter(networkStream);
} }
catch
{
statusStripInfo.Invoke(showStatusCallBack,"连接失败");
Thread.Sleep();
statusStripInfo.Invoke(showStatusCallBack,"就绪");
}
}

客户端发送消息的代码:

 // 发送消息
private void btnSend_Click(object sender, EventArgs e)
{
Thread sendThread = new Thread(SendMessage);
sendThread.Start(tbxMessage.Text);
} private void SendMessage(object state)
{
statusStripInfo.Invoke(showStatusCallBack, "正在发送...");
try
{
writer.Write(state.ToString());
Thread.Sleep();
writer.Flush();
statusStripInfo.Invoke(showStatusCallBack, "完毕"); tbxMessage.Invoke(resetMessageCallBack, null);
lstbxMessageView.Invoke(showMessageCallback, state.ToString());
}
catch
{
if (reader != null)
{
reader.Close();
}
if (writer != null)
{
writer.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
} statusStripInfo.Invoke(showStatusCallBack, "断开了连接");
}
}

服务器端接受开始监听客户端请求的代码:

 // 开始监听
private void btnStart_Click(object sender, EventArgs e)
{ tcpLister = new TcpListener(ipaddress,Port);
tcpLister.Start();
// 启动一个线程来接受请求
Thread acceptThread =new Thread(acceptClientConnect);
acceptThread.Start();
} // 接受请求
private void acceptClientConnect()
{
statusStripInfo.Invoke(showStatusCallBack,"正在监听");
Thread.Sleep();
try
{
statusStripInfo.Invoke(showStatusCallBack,"等待连接");
tcpClient = tcpLister.AcceptTcpClient();
if (tcpLister != null)
{
statusStripInfo.Invoke(showStatusCallBack,"接受到连接");
networkStream = tcpClient.GetStream();
reader = new BinaryReader(networkStream);
writer = new BinaryWriter(networkStream);
}
}
catch
{
statusStripInfo.Invoke(showStatusCallBack, "停止监听");
Thread.Sleep();
statusStripInfo.Invoke(showStatusCallBack, "就绪");
}
}

现在看看运行的结果:
首先先启动服务器然后点开始监听,此时线程会堵塞,直到接受到一个连接请求位置。

然后运行客户端,在IP地址和端口处输入服务器端的IP地址和端口号,点击连接服务器按钮后的界面如下:

通过接受按钮和发送按钮来实现双方的通信,实现界面如下:

三、总结

到这里本专题的内容将的差不多了, 本专题主要介绍了基于TCP协议工作过程和在net平台下自定义了一个简单通信的程序,希望本专题可以给那些初次接触TCP协议的朋友一些帮助,(大牛们应该直接可以闪过的),在后面的专题我将和大家分享UDP编程,讲完UDP编程后将结合这两章的内容实现一个类似QQ的即时聊天的工具,希望这些对大家有帮助,如果大家有任何问题和有感兴趣的专题需要了解的,可以给我留言,在之后的文章都会和大家来分享。

转自:http://www.cnblogs.com/zhili/archive/2012/08/25/TCP.html

专题五:TCP编程的更多相关文章

  1. [C# 网络编程系列]专题五:TCP编程

    转自:http://www.cnblogs.com/zhili/archive/2012/08/25/2656840.html 前言 前面专题的例子都是基于应用层上的HTTP协议的介绍, 现在本专题来 ...

  2. 转:【专题五】TCP编程

    前言 前面专题的例子都是基于应用层上的HTTP协议的介绍, 现在本专题来介绍下传输层协议——TCP协议,主要介绍下TCP协议的工作过程和基于TCP协议的一个简单的通信程序,下面就开始本专题的正文了. ...

  3. 五十四、linux 编程——TCP 编程模型

    54.1 编程模型介绍 54.1.1 TCP 客户端服务器编程模型 客户端调用序列 调用 socket 函数创建套接字 调用 connect 连接服务器端 调用 I/O 函数(read/write) ...

  4. python中的TCP编程学习

    今天看了一下关于python的TCP编程. 发现思路和其他语言(比如java)思路基本上差点儿相同. 先看client.基本过程例如以下: 第一步:创建一个socket 第二步:建立连接 第三步:发送 ...

  5. 20155324 《Java程序设计》实验五 网络编程与安全

    20155324 <Java程序设计>实验五 网络编程与安全 实验内容 任务一 编写MyBC.java实现中缀表达式转后缀表达式的功能 编写MyDC.java实现从上面功能中获取的表达式中 ...

  6. 20165317Java实验五 网络编程与安全

    实验五 网络编程与安全 一.中缀转后缀 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA 结对实现中缀表达式转后缀表达式的功能 MyBC.ja ...

  7. 20155326 《Java程序设计》实验五网络编程与安全实验报告

    20155326 <Java程序设计>实验五网络编程与安全实验报告 实验内容 任务一 1.两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/67667 ...

  8. #《JAVA程序设计》 20155214 实验五 网络编程与安全

    <JAVA程序设计> 20155214 实验五 网络编程与安全 实验内容 掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验要求 要求一 结对实现中缀表达式转后缀 ...

  9. 20155301 《Java程序设计》实验五网络编程与安全

    20155301 <Java程序设计>实验五网络编程与安全 实验内容 实验1: 两人一组结对编程:参考http://www.cnblogs.com/rocedu/p/6766748.htm ...

随机推荐

  1. Letter Combinations of a Phone Number(带for循环的DFS,组合问题,递归总结)

    Given a digit string, return all possible letter combinations that the number could represent. A map ...

  2. bzoj3190【JLOI2013】赛车

    3190: [JLOI2013]赛车 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1445  Solved: 454 [Submit][Statu ...

  3. [TypeScript] Collect Related Strings in a String Enum in TypeScript

    As of TypeScript 2.4, it is now possible to define string enums, or more precisely, enums with strin ...

  4. Java RMI之HelloWorld程序以及相关的安全管理器的知识

    Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,可以让在某个 Java 虚拟机上的对象调用还有一个 Java 虚拟机中的对象上的方法.可以用此 ...

  5. SQLServer时间分段查询

    统计连续时间段数据 if OBJECT_ID(N'Test',N'U') is not null drop table Test go create table Test( pscode decima ...

  6. 12、Cocos2dx 3.0游戏开发找小三之3.0中的生命周期分析

    重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27706303 生命周期分析 在前面文章中我们执行了第 ...

  7. EXCEL单元格的获取——多例模式

    因为Excel的单元格的行列与单元格是一一相应的,行与列组成的是一对联合主键.给定一个单元格行列或者给定一个单元格名称.须要找到相应的单元格:这样就形成了一种映射关系.须要使用单例模式的变式--多例模 ...

  8. 模式识别之车牌识别---一个开源车牌识别项目easypr

    http://doc.okbase.net/subconscious/archive/105312.html https://github.com/liuruoze http://www.cnblog ...

  9. ios22--动画

    控制器: // // ViewController.m // 07-渐变动画 // // Created by xiaomage on 15/12/30. // Copyright © 2015年 小 ...

  10. [USACO15DEC]High Card Low Card (Platinum)

    https://www.zybuluo.com/ysner/note/1300791 题面 贝西和她的朋友艾尔西正在玩这个简单的纸牌游戏.游戏有\(2N\)张牌,牌上的数字是\(1\)到\(2N\). ...