我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念:

  1. TCP/IP层次模型

当然这里我们只讨论重要的四层

01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用。http协议在应用层运行。

02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP

提供传输保证。

03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

04,链路层(Link):又称为物理数据网络接口层,负责报文传输。

然后我们来看下tcp层次模型图

从上图中可以看出,应用程序在应用层运行,在传输层,在数据前加上了TCP头,在

网络层加上的IP头,在数据链路层加上了帧。

2,端口

端口号范围:0-65535,总共能表示65536个数。

   按端口号可分为3大类

  (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。

  (2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。

  (3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。

3.TCP和UDP报文

下面一起来看下TCP和UDP的报文图

从图中我们可以看出TCP和UDP中都有校验和,但是在UDP报文中,一般不使用校验和,这样可以加快数据传输的速度,但是数据的准确性可能会受到影响。换句话说,Tcp协议都有校验和,为了保证传输数据的准确性。

3.Socket

Socket包括Ip地址和端口号两部分,程序通过Socket来通信,Socket相当于操作系统的一个组件。Socket作为进程之间通信机制,通常也称作”套接字”,用于描述IP地址和端口号,是一个通信链的句柄。说白了,就是两个程序通信用的。

生活案例对比:

Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。

注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。

4,端口进阶(深入)

通过IP地址确定了网络中的一台电脑后,该电脑上可能提供很多提供服务的应用,每一个应用都对应一个端口。

在Internet上有很多这样的主机,这些主机一般运行了多个服务软件 ,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)

例如:http 使用80端口,   ftp使用21端口     smtp使用25端口

5.Socket分类

Socket主要有两种类型:

  1. 流式Socket

是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低

2,数据报式Socket

是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高

6. Socket一般应用模式(服务器端和客户端)

服务器端的Socket(至少需要两个)

01.一个负责接收客户端连接请求(但不负责与客户端通信)

02.每成功接收到客户端的连接便在服务器端产生一个对应的复杂通信的Socket

021.在接收到客户端连接时创建

022. 为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)

客户端的Socket

  1. 必须指定要连接的服务器地址和端口
  2. 通过创建一个Socket对象来初始化一个到服务器端的TCP连接

通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。

下面我们来看下Socket更具体的通信过程:

Socket的通讯过程

服务器端:

01,申请一个socket

02,绑定到一个IP地址和一个端口上

03,开启侦听,等待接收连接

客户端:

01,申请一个socket

02,连接服务器(指明IP地址和端口号)

服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。

注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。

7.Socket的构造函数

Public Socket(AddressFamily addressFamily,SocketType  socketType,ProtocolType  protocolTYpe)

AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接

SocketType:定义要打开的Socket的类型

Socket类使用ProtocolType枚举向Windows  Sockets  API通知所请求的协议

注意:

1,端口号必须在 1 和 65535之间,最好在1024以后。

2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。

如:

IPAddress addr = IPAddress.Parse("127.0.0.1");

IPEndPoint endp = new IPEndPoint(addr,,9000);

服务端先绑定:serverWelcomeSocket.Bind(endp)

客户端再连接:clientSocket.Connect(endp)

3,一个Socket一次只能连接一台主机

4,Socket关闭后无法再次使用

5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。

8.Socket常用类和方法

相关类:

IPAddress:包含了一个IP地址

IPEndPoint:包含了一对IP地址和端口号

方法:

Socket():创建一个Socket

Bind():绑定一个本地的IP和端口号(IPEndPoint)

Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量

Connect():初始化与另一个Socket的连接

Accept():接收连接并返回一个新的Socket

Send():输出数据到Socket

Receive():从Socket中读取数据

Close():关闭Socket,销毁连接

接下来,我们同一个简单的服务器和客户端通信的案例,来看下Sokcet的具体用法,效果图如下:


关键代码:

服务器端代码:

private void Form1_Load(object sender, EventArgs e)

 

        {

 

            Control.CheckForIllegalCrossThreadCalls = false;

 

        }

 

 

 

        private void btnListen_Click(object sender, EventArgs e)

 

        {

 

            //ip地址

 

            IPAddress ip = IPAddress.Parse(txtIP.Text);

 

           // IPAddress ip = IPAddress.Any;

 

            //端口号

 

            IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));

 

            //创建监听用的Socket

 

            /*


             * AddressFamily.InterNetWork:使用 IP4地址。


SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。


ProtocolType.Tcp:使用传输控制协议。


             */

 

            //使用IPv4地址,流式socket方式,tcp协议传递数据

 

            Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

 

            //创建好socket后,必须告诉socket绑定的IP地址和端口号。

 

            //让socket监听point

 

            try

 

            {

 

                //socket监听哪个端口

 

                socket.Bind(point);

 

                //同一个时间点过来10个客户端,排队

 

                socket.Listen(10);

 

                ShowMsg("服务器开始监听");

 

                Thread thread = new Thread(AcceptInfo);

 

                thread.IsBackground = true;

 

                thread.Start(socket);

 

            }

 

            catch (Exception ex)

 

            {

 

               

 

               ShowMsg(ex.Message);

 

            }

 

        }

 

        //记录通信用的Socket

 

        Dictionary<string,Socket> dic=new Dictionary<string, Socket>();

 

       // private Socket client;

 

        void AcceptInfo(object o)

 

        {

 

            Socket socket = o as Socket;

 

            while (true)

 

            {

 

                //通信用socket

 

                try

 

                {

 

                    //创建通信用的Socket

 

                  Socket  tSocket = socket.Accept();

 

                  string point = tSocket.RemoteEndPoint.ToString();

 

                    //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;

 

                    //string me = Dns.GetHostName();//得到本机名称

 

                    //MessageBox.Show(me);

 

                 ShowMsg(point + "连接成功!");

 

                 cboIpPort.Items.Add(point);

 

                 dic.Add(point, tSocket);

 

                    //接收消息

 

                    Thread th = new Thread(ReceiveMsg);

 

                    th.IsBackground = true;

 

                    th.Start(tSocket);

 

                }

 

                catch (Exception ex)

 

                {

 

                    ShowMsg(ex.Message);

 

                    break;

 

                }

 

            }

 

        }

 

        //接收消息

 

        void ReceiveMsg(object o)

 

        {

 

            Socket client = o as Socket;

 

            while (true)

 

            {

 

                //接收客户端发送过来的数据

 

                try

 

                {

 

                    //定义byte数组存放从客户端接收过来的数据

 

                    byte[] buffer = new byte[1024 * 1024];

 

                    //将接收过来的数据放到buffer中,并返回实际接受数据的长度

 

                    int n = client.Receive(buffer);

 

                    //将字节转换成字符串

 

                    string words = Encoding.UTF8.GetString(buffer, 0, n);

 

                  

 

                    ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);

 

                }

 

                catch (Exception ex)

 

                {

 

                   ShowMsg(ex.Message);

 

                    break;

 

                }

 

            }

 

        }

 

 

 

        void ShowMsg(string msg)

 

        {

 

            txtLog.AppendText(msg+"\r\n");

 

        }

 

 

 

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)

 

        {

 

            //主窗体关闭时关闭子线程

 

          

 

        }

 

        //给客户端发送消息

 

        private void btnSend_Click(object sender, EventArgs e)

 

        {

 

            try

 

            {

 

                ShowMsg(txtMsg.Text);

 

                string ip = cboIpPort.Text;

 

                byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

 

                dic[ip].Send(buffer);

 

                // client.Send(buffer);

 

            }

 

            catch (Exception ex)

 

            {

 

               ShowMsg(ex.Message);

 

            }

 

 

 

        }

客户端代码:

Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 

        private void btnConnection_Click(object sender, EventArgs e)

 

        {

 

            //连接到的目标IP

 

            IPAddress ip = IPAddress.Parse(txtIP.Text);

 

            //IPAddress ip = IPAddress.Any;

 

            //连接到目标IP的哪个应用(端口号!)

 

            IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));

 

            try

 

            {

 

                //连接到服务器

 

                client.Connect(point);

 

                ShowMsg("连接成功");

 

                ShowMsg("服务器" + client.RemoteEndPoint.ToString());

 

                ShowMsg("客户端:" + client.LocalEndPoint.ToString());

 

                //连接成功后,就可以接收服务器发送的信息了

 

                Thread th=new Thread(ReceiveMsg);

 

                th.IsBackground = true;

 

                th.Start();

 

            }

 

            catch (Exception ex)

 

            {

 

                ShowMsg(ex.Message);

 

            }

 

        }

 

        //接收服务器的消息

 

        void ReceiveMsg()

 

        {

 

            while (true)

 

            {

 

                try

 

                {

 

                    byte[] buffer = new byte[1024 * 1024];

 

                    int n = client.Receive(buffer);

 

                    string s = Encoding.UTF8.GetString(buffer, 0, n);

 

                    ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);

 

                }

 

                catch (Exception ex)

 

                {

 

                    ShowMsg(ex.Message);

 

                    break;

 

                }

 

            }

 

          

 

        }

 

 

 

        void ShowMsg(string msg)

 

        {

 

            txtInfo.AppendText(msg+"\r\n");

 

        }

 

 

 

        private void btnSend_Click(object sender, EventArgs e)

 

        {

 

            //客户端给服务器发消息

 

            if (client!=null)

 

            {

 

                try

 

                {

 

                   ShowMsg(txtMsg.Text);

 

                    byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

 

                    client.Send(buffer);

 

                }

 

                catch (Exception ex)

 

                {

 

                   ShowMsg(ex.Message);

 

                }

 

            }

 

           

 

        }

 

 

 

        private void ClientForm_Load(object sender, EventArgs e)

 

        {

 

            Control.CheckForIllegalCrossThreadCalls = false;

 

        }

好了,到这里我们对Socket的讨论就告一个段落了。

C# Socket网络编程精华篇(转)的更多相关文章

  1. C# Socket网络编程精华篇 (转)

    http://www.cnblogs.com/weilengdeyu/archive/2013/03/08/2949101.html 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的 ...

  2. C# Socket网络编程精华篇

    我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次模型 当然这里我们只讨论重要的四层 01,应用层(Application):应用层是个很广泛的概念,有一些基本 ...

  3. Socket网络编程精华篇

    几个和Socket编程紧密相关的概念: TCP/IP层次模型 当然这里我们只讨论重要的四层 01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应 ...

  4. Socket网络编程-基础篇

    Socket网络编程 网络通讯三要素: IP地址[主机名] 网络中设备的标识 本地回环地址:127.0.0.1 主机名:localhost 端口号 用于标识进程的逻辑地址 有效端口:0~65535 其 ...

  5. java架构《Socket网络编程基础篇》

    本章主要介绍Socket的基本概念,传统的同步阻塞式I/O编程,伪异步IO实现,学习NIO的同步非阻塞编程和NIO2.0(AIO)异步非阻塞编程. 目前为止,Java共支持3种网络编程模型:BIO.N ...

  6. socket网络编程扫盲篇

    socket 是“套接字”的意思,是计算机之间进行通信的一种约定,也可以认为是一种技术.通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据. socket 的 ...

  7. Socket网络编程(TCP/IP/端口/类)和实例

    Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次 ...

  8. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  9. Socket网络编程(2)--服务端实现

    中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...

随机推荐

  1. ubuntu修改grub界面默认开机顺序

    终端输入: sudo gedit /etc/default/grub GRUB_DEFAULT代表的就是启动项的顺序,从数字0开始 修改成默认的第几个,就赋值成几就好(顺序从数字0开始) 然后别忘了运 ...

  2. 转-WebView loadData与loadDataWithBaseURL用法、区别

    近期用到WebView加载一些动态的内容的时候遇到一些问题,例如:在加载动态网页时,页面有很多样式表包含一些特殊字符,导致WebView无法识别产生加载异常,程序直接崩溃:另外一个就是加载的网页中有图 ...

  3. 通过Application传递数据代码

    使用Application传递数据步骤如下:创建新class,取名MyApp,继承android.app.Application父类,并在MyApp中定义需要保存的属性     在整个Android程 ...

  4. Think in UML笔记第1章--为什么要UML

    1.1 面向过程还是面向对象 面向过程和面向对象都是一种软件技术.例如把面向过程归纳为结构化程序设计.DFD图.ER模型.UC矩阵等,而面向对象则被归纳为继承.封装.多态.复用等具体的技术.事实上,上 ...

  5. Jquery Validation 插件验证手机号

    自定义手机号验证代码  http://www.2cto.com/kf/201505/402781.html // 手机号码验证 jQuery.validator.addMethod("isM ...

  6. 手动编码运行java程序

    javac Server.java 编译java文件成class java Server 运行程序

  7. 去掉 input type="number" 右边图标

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. DELPHI SOKET 编程(使用TServerSocket和TClientSocket) 转

    http://www.cnblogs.com/findumars/p/5272658.html   本文采用delphi7+TServerSocket+TClientSocket; 笔者在工作中遇到对 ...

  9. [转载]python中将普通对象作为 字典类(dict) 使用

    目前我知道的有两种方法: 1 定义的类继承dict类 例如 class A(dict): pass a = A() a['name'] = 12 2 给自定义的类添加 __setitem__() __ ...

  10. Regex.Replace的基本用法

    Regex构造函数Regex(string pattern)Regex(string pattern,RegexOptions options)参数说明pattern:要匹配的正则表达式模式optio ...