socket编程详解,转自http://www.sme-cn.com:82/archives/669
一 Socket简介
- Socket翻译过来是套接字,具体含义可自行百度,简言之就是IP:Port的组合,是网络通信的一个窗口,IP就是地址和门牌号(比如长沙市韶山北路81号),Port就是房间号(比如6楼611室)。
- Visual Studio(简称VS)中System.Net.Sockets命名空间就是提供Socket网络应用的相关类的,其中Socket类、TcpClient类、TcpServer类、TcpListener类较为常用,是实现Socket网络通信必备的。至于“命名空间”、“类”等术语限于篇幅请自行百度。
- 我们常用的SocketTool.exe就是用Socket技术实现的。
- Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。
- Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。
二 Socket一般应用模式
Socket一般应用模式即:客户端、服务器模式
服务器端侦听一般会打开至少两个Socket
01.一个负责接收客户端连接请求(但不负责与客户端通信)
02.每成功接收到客户端的连接便在服务器端产生一个与之对应的通信的Socket,该Socket是在接收到客户端连接时就会创建的,为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)
客户端的Socket
01.必须指定要连接的服务器地址和端口
02.通过创建一个Socket对象来初始化一个到服务器端的TCP连接
下面是一张服务器、客户端Socket通信的原理图
下面我们来看下Socket更具体的通信过程:
服务器端:
01,申请一个socket
02,绑定到一个IP地址和一个端口上
03,开启侦听,等待接收连接
客户端:
01,申请一个socket
02,指定要连接的服务器(指明服务器的IP地址和端口号)
服务器端:
01.接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信(就相当于公司的前台)
02.原监听socket继续监听。
注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。
2.1 Socket构造函数
Socket的构造函数
Public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolTYpe)
各参数的含义:
AddressFamily:指定Socket用来解析地址的寻址方案
SocketType:定义要打开的Socket的类型
Socket类使用ProtocolType枚举向Windows Sockets API通知所请求的协议
注意:
1,端口号必须在 1 和 65535之间,最好在1024以后(1024以内的端口一般都是系统定义的端口,最好不要占用)。
2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。
如:
IPAddress addr = IPAddress.Parse(“192.168.1.118″);
IPEndPoint endp = new IPEndPoint(addr,9000);
服务端先绑定:serverSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
3,一个客户端Socket一次只能连接一台主机(服务器端)
4,Socket关闭后无法再次使用
5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。
2.2 Socket常用类和方法
相关类:
IPAddress:包含了一个IP地址
IPEndPoint:包含了一对IP地址和端口号
方法:
Socket():创建一个Socket
Bind():绑定一个本地的IP和端口号(IPEndPoint)
Listen():让Socket侦听传入的连接(俗称:等待上线),并指定侦听队列容量
Connect():初始化与另一个Socket的连接
Accept():接收连接并返回一个新的Socket
Send():输出数据到Socket
Receive():从Socket中读取数据
Close():关闭Socket,销毁连接
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; namespace ASimpleSocketComm { public partial class frm_Server : Form { public frm_Server() { InitializeComponent(); } //窗体加载事件 private void Form1_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; } //开始侦听 按钮单击事件 private void btn_StartLsn_Click(object sender, EventArgs e) { //获取输入框中的IP地址 IPAddress myip = IPAddress.Parse(txt_IP.Text); //获取输入框中的端口号 int myport = int.Parse(txt_Port.Text); //构建IP终结点 IPEndPoint ippoint = new IPEndPoint(myip, myport); //创建监听用的Socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //解释:第一个参数代表使用IPV4寻址方案,第二个参数是指采用Stream方式进行通信,第三个参数是指基于TCP协议 try { //将创建好的socket绑定到具体的IP终结点 socket.Bind(ippoint); //同一时间最多接收10个客户端上线,多余的需排队 socket.Listen(); //在Server窗体中显示信息 txt_SrvMsg.AppendText("服务器开始侦听...\r\n"); Thread mythread = new Thread(AcceptInfo); mythread.IsBackground = true; mythread.Start(socket); } catch (Exception ex) { txt_SrvMsg.AppendText(ex.Message + "\r\n"); } } //记录通信用的Socket Dictionary<string, Socket> dic = new Dictionary<string, Socket>(); //侦听并接收客户端上线连接 void AcceptInfo(object o) { Socket socket = o as Socket; //循环接收消息 死循环 while (true) { try { //创建通信用的socket Socket tScocket = socket.Accept(); string ippoit = tScocket.RemoteEndPoint.ToString(); txt_SrvMsg.AppendText(ippoit + "连接成功!\r\n"); dic.Add(ippoit, tScocket);//将连接上来的客户端IPPORT保存到dic中 cbx_IPEndPoint.Items.Add(ippoit);//将连接上来的客户端IPPORT添加到下拉框中 //接收消息 Thread th = new Thread(ReceiveMsg); th.IsBackground = true; th.Start(tScocket); } catch (Exception ex) { txt_SrvMsg.AppendText(ex.Message + "\r\n"); break; } } } //接收客户端发送的消息 void ReceiveMsg(object o) { Socket client = o as Socket; while (true) { //接收客户端发送过来的数据 try { //定义byte数组存放从客户端接收到的数据 * ]; //将接收的数据放入buffer中,并返回实际接收数据的长度 int n = client.Receive(buffer); //将字节数组转换成字符串 , n); //将接收的数据显示到Server窗体中 txt_SrvMsg.AppendText(client.RemoteEndPoint.ToString() + ":" + words + "\r\n"); } catch (Exception ex) { txt_SrvMsg.AppendText(ex.Message + "\r\n"); break; } } } //给客户端发送消息 发送消息按钮单击事件 private void btn_SendMsg_Click(object sender, EventArgs e) { try { //设置发送目标客户端 string ipport = cbx_IPEndPoint.Text;//从下拉框中获取选中的目标IPPORT if (ipport == "") { MessageBox.Show("请选择一个客户端!"); return; } //将要发送的数据转换为byte数组 byte[] buffer = Encoding.Default.GetBytes(txt_Send.Text); //发送数据 dic[ipport].Send(buffer); //将要发送的数据显示到Server窗体中 txt_SrvMsg.AppendText(txt_Send.Text + "\r\n"); } catch (Exception ex) { txt_SrvMsg.AppendText(ex.Message + "\r\n"); } } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; namespace ASimpleSocketClient { public partial class frm_Client : Form { public frm_Client() { InitializeComponent(); } //窗体加载事件 private void frm_Client_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; } Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //连接 按钮单击事件 private void btn_Connect_Click(object sender, EventArgs e) { //需要连接的目标IP(服务器端的IP) IPAddress ip = IPAddress.Parse(txt_IP.Text); //目标端口(服务器端的侦听端口) int port = int.Parse(txt_Port.Text); //构建IP终结点 IPEndPoint ippoint = new IPEndPoint(ip, port); try { //连接到服务器 client.Connect(ippoint); txt_ClientMsg.AppendText("连接成功!" + "\r\n"); txt_ClientMsg.AppendText("服务器:" + client.RemoteEndPoint.ToString() + "\r\n"); txt_ClientMsg.AppendText("客户端:" + client.LocalEndPoint.ToString() + "\r\n"); //连接成功后就可以接收服务器端发送的消息了 Thread th = new Thread(ReceiveMsg); th.IsBackground = true; th.Start(); } catch (Exception ex) { txt_ClientMsg.AppendText(ex.Message + "\r\n"); } } //接收服务器端发送的消息 void ReceiveMsg() { while (true) { try { * ]; int n = client.Receive(buffer); , n); txt_ClientMsg.AppendText(client.RemoteEndPoint.ToString() + ":" + s + "\r\n"); } catch (Exception ex) { txt_ClientMsg.AppendText(ex.Message + "\r\n"); break; } } } //发送消息 按钮单击事件 private void btn_SendMsg_Click(object sender, EventArgs e) { //客户端给服务器端发送消息 if (client != null) { try { byte[] buffer = Encoding.Default.GetBytes(txt_Send.Text); client.Send(buffer); txt_ClientMsg.AppendText(txt_Send.Text + "\r\n"); } catch (Exception ex) { txt_ClientMsg.AppendText(ex.Message + "\r\n"); } } } } }
最新文章
- CentOS 6.3下Samba服务器的安装与配置方法(图文详解)
- 搭建haproxy
- DDD~领域事件与事件总线
- 那些年,在AngularJS的路上遇到的坑
- python 判断学期与学年
- LightOJ1031 Easy Game(区间DP)
- 2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred) 几道简单题的题解
- JDK + Tomcat 安装配置
- FileUtils类应该有哪些内容
- php 7 正式发版
- asp 操作 json
- 基于vue的颜色选择器color-picker
- 珍爱生命,远离JS=>;JS避坑记
- FusionCharts中图的属性的总结归纳
- Java多线程的调度策略
- 暑假闲着没事第一弹:基于Django的长江大学教务处成绩查询系统
- Java接口自动化测试之集成MyBatis和MySQL (五)
- 01-Introspector内省机制
- Spark学习之路 (三)Spark之RDD
- A计划 hdu2102(bfs一般题)