TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的;然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多。C#通过提供的Socket API实现了对TCP/IP协议栈的封装,让实现C/S模型变得更加简单,对于入门TCP/IP协议学习十分有帮助。

   Socket通讯实现参考标准的流程如图所示,

·

  服务器工作:

  1.创建Socket套接字,绑定指定host,并监听。

2.线程堵塞等待用户端请求,当客户端请求到达时建立连接。

  3.连接建立完成后,读取请求并处理,然后将处理结果返回给客户端。

  4. 服务器等待客户端关闭连接,连接关闭后,一次Socket通讯结束。

客户端工作:

   1.创建Socket套接字, 建立连接,发送连接请求数据

2. 请求成功后,等待服务器返回响应

3.服务器回应成功后,处理数据,直到主动关闭连接。

  了解了上述Socket通讯的主要过程,在结合C#网络编程的特性,就可以实现如下C/S服务器。客户端的实现比较简单,主要分四个步骤:

  1.建立tcp连接(等同于socket 和 connect),处理连接失败状态

2.对于建立成功的连接,发送数据,并等待服务器返回

3.接收数据,输出到编辑框

4.关闭连接

private void button1_Click(object sender, EventArgs e)
{
try
{
string s_ipaddress0 = textBox1.Text;
string s_ipaddress1 = textBox2.Text;
string s_ipaddress2 = textBox3.Text;
string s_ipaddress3 = textBox4.Text;
string s_port = textBox5.Text; //限定port的合法性
bool isPort;
int port;
isPort = Int32.TryParse(s_port, out port);
if (!(isPort && port >= && port <= ))
{
OutToClient("Port is Invalid!");
return;
} //限定ip地址的合法性
string host = s_ipaddress0 + "." + s_ipaddress1 + "." + s_ipaddress2 + "." + s_ipaddress3;
if (!IsIpAdress(host))
{
OutToClient("IpAdress is invaild!");
return;
}
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port); //Ip端口绑定 如192.168.1.48:80 //发送框不能为空, 不然会导致GetBytes出错
if (textBox6.Text == "")
{
OutToClient("Send Text is empty!");
return;
} OutToClient("Conneting..."); int timeout = ; //tcpClient连接到指定端口,并处理超时
TcpClient NetworkClient = TimeOutSocket.Connect(ipe, timeout);
NetworkStream ntwStream = NetworkClient.GetStream();
if (!ntwStream.CanWrite)
{
OutToClient("Data can not be write!");
return;
} //向绑定地址端口发送数据
OutToClient("Client send:" + textBox6.Text);
string sendStr = textBox6.Text;
byte[] by_send = Encoding.ASCII.GetBytes(sendStr);
ntwStream.Write(by_send, , by_send.Length); //等待服务器端返回数据
string recvStr = "";
byte[] recvBytes = new byte[];
int bytes = ntwStream.Read(recvBytes, , recvBytes.Length); //将接收到数据转发输出到Client编辑框
recvStr += Encoding.ASCII.GetString(recvBytes, , bytes);
OutToClient(recvStr); //关闭连接, 一次发送完成
ntwStream.Close();
NetworkClient.Close();
OutToClient("Conneting Close!\r\n");
}
catch (ArgumentNullException ii)
{
OutToClient("ArgumentNullException: "+ ii);
}
catch (SocketException ii)
{
OutToClient("Socket failed! ");
}
catch (Exception ii)
{
OutToClient("Conneting faild!" + ii);
}
}

  服务器内的代码涉及到的知识多一些

1.通过按键1开辟监听线程,用于接收

2.监听线程创建Socket套接字,绑定到指定端口并监听

3.监听线程堵塞在等带连接建立

4.连接建立后监听线程读取客户端数据并回送给客户端处理后数据,然后循环堵塞在连接建立

5.通过按键2删除Socket套接字触发异常,结束线程

按照上述的流程,程序如下:

//新建线程 开始监听
private void button1_Click(object sender, EventArgs e)
{
try
{
isConnectExit = false;
button1.Enabled = false;
button2.Enabled = true; Thread Listen_thread = new Thread(ListenClientConnect);
Listen_thread.IsBackground = true;
Listen_thread.Start();
}
catch (Exception ii)
{
OutToServer("Connet faild!" + ii);
}
}
//监听线程 主要处理数据接收发送
private void ListenClientConnect(object obj)
{
string s_ipaddress0 = textBox1.Text;
string s_ipaddress1 = textBox2.Text;
string s_ipaddress2 = textBox3.Text;
string s_ipaddress3 = textBox4.Text;
string s_port = textBox5.Text; //限定port的合法性
bool isPort;
int port;
isPort = Int32.TryParse(s_port, out port);
if (!(isPort && port >= && port <= ))
{
OutToServer("Port is Invalid!");
return;
} //限定ip地址的合法性
string host = s_ipaddress0 + "." + s_ipaddress1 + "." + s_ipaddress2 + "." + s_ipaddress3;
if (!IsIpAdress(host))
{
OutToServer("IpAdress is invaild!");
return;
} IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port); //新建socket通讯 绑定指定IP+Port 并监听
server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server_socket.Bind(ipe);
server_socket.Listen(); OutToServer("wait for connect...");
while (isConnectExit == false)
{
Socket CurrentSocket;
try
{
//等待连接 完成三次握手
CurrentSocket = server_socket.Accept();
if(isConnectExit == true)
{
CurrentSocket.Close(); // 关闭Socket
server_socket.Close();
break;
}
OutToServer("Get a Connect!");
ServerProcess(CurrentSocket);
}
catch
{
OutToServer("Connet exti!");
}
}
}
//断开连接
private void button2_Click(object sender, EventArgs e)
{
isConnectExit = true;
button2.Enabled = false;
button1.Enabled = true;
if (server_socket != null)
{
server_socket.Close();
}
}

如此就完成了简单的C/S服务器功能。

实际测试界面如下:

具体源码参考:C/S架构客户端-服务器下载

备注:本程序仅用于演示TCP socket通信流程,服务器端能够监听的IP地址只有本机IP或者127.x.x.1(环回地址), 端口不能为80(和本机http端口冲突)。

TCP/IP协议学习(五) 基于C# Socket的C/S模型的更多相关文章

  1. TCP/IP协议学习(四) 基于C# Socket的Web服务器---静态资源处理

    目录 1. C# Socket通讯 2. HTTP 解析引擎 3. 资源读取和返回 4. 服务器测试和代码下载 Web服务器是Web资源的宿主,它需要处理用户端浏览器的请求,并指定对应的Web资源返回 ...

  2. TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现

    目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...

  3. TCP/IP协议学习之实例ping命令学习笔记

    TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...

  4. TCP/IP协议学习(四) 协议概述

    生活中有舒适区,借口成为懒惰的护身符,学习也有舒适区,逃避便是阻止进步的最大障碍. 经过半年多嵌入式方面的工作和学习,我提高了很多,但同时我也对自己所面临的问题逐渐清晰: 1. 偏于实践,理论基础不牢 ...

  5. tcp/ip协议学习笔记一

    一. 简述 以前在学校学习计算机网络的时候学习多是网络7层模型OSI,了解了一些基本的计算机网络概念和协议通信格式,但是一直没弄明白其中的原理,包括各层之间的关系,应用,还有一些常见的令牌环网到底是什 ...

  6. TCP/IP协议学习笔记

    计算机网络基础知识复习汇总:计算机网络基础知识复习 HTTP协议的解析:剖析 HTTP 协议 一个系列的解析文章: TCP/IP详解学习笔记(1)-- 概述 TCP/IP详解学习笔记(2)-- 数据链 ...

  7. TCP/IP协议学习-1.概述

    目录 TCP/IP协议概述 分层 延伸知识 FTP例子 为什么需要网络层和传输层 TCP/IP的分层 封装 分用 总结 本文主要摘抄自书籍<TCP/IP详解卷一:协议>与TCP协议相关内容 ...

  8. TCP/IP协议学习和理解

    TCP:Transmission Control Protocol-传输控制协议 IP:Internet Protocol-网络协议 TCP/IP 不是一个协议,而是一个协议族的统称,里面包括了 IP ...

  9. TCP/IP协议学习

    计算机网路学得不好,首先先放个OSI七层网络模型吧 在协议的控制下,上层对下层进行调用,下层对上层进行服务, 上下层间用交换原语交换信息.这样可以提高传输速率,并且保证数据安全,所以说其实每一层都有存 ...

随机推荐

  1. 。。。IO流学习之二。。。

    fileReader的用法: import static org.junit.Assert.*; import java.io.File; import java.io.FileNotFoundExc ...

  2. Javascript模块化编程(二):AMD规范(转)

    这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要 ...

  3. github android

    作者:ruijun 链接:https://www.zhihu.com/question/37160415/answer/79569042 来源:知乎 著作权归作者所有,转载请联系作者获得授权. ### ...

  4. 非常强大的table根据表头排序,点击表头名称,对其内容排序

    js代码: /** * 通过表头对表列进行排序 * * @param sTableID * 要处理的表ID<table id=''> * @param iCol * 字段列id eg: 0 ...

  5. [Silverlight]监听指定控件(FrameworkElement)的依赖属性(DependencyProperty)的更改

    前言 转载请注明出处:http://www.cnblogs.com/ainijiutian 最近在silverlight项目使用Telerik的控件,遇到一个问题.就是使用RadBusyIndicat ...

  6. Java反射遍历数组

    日志中有时候需要查看数组中的值,但是重载很多的打印函数,觉得很别扭.所以想通过反射,获取数组中的值,打印出来.Java提供了数组反射操作的类,之前没有关注过,提供的方法简单易用. public sta ...

  7. django 其他地址访问不了问题

    启动的时候 使用 python manage.py runserver 0.0.0.0:8000  即可接收所有IP访问

  8. 利用 async & await 的异步编程

    走进异步编程的世界 - 开始接触 async/await 利用 async & await 的异步编程 async 的三大返回类型 公司技术需求备忘录

  9. Breeze库API总结(Spark线性代数库)(转载)

    导入 import breeze.linalg._ import breeze.numerics._ Spark Mllib底层的向量.矩阵运算使用了Breeze库,Breeze库提供了Vector/ ...

  10. nodejs学习笔记二:解析express框架项目文件

    上一章介绍了如何去创建一个express框架的工程项目,这章介绍一下express框架下的文件和用法解析,上一张我们创建的工程项目结构图如下: models是不属于原工程项目结构,为了实现数据模型后添 ...