1、Socket相关概念[端口]
2、Socket一般应用模式(服务器端和客户端)
3、Socket的通讯过程
4、Socket的构造函数
5、Socket通信基本流程图
6、基于TCP的Socket编程
7、Socket源代码
1、Socket相关概念[端口]
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。
每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)。
例如:http 使用80端口 ftp使用21端口 smtp 25端口
有两种类型:50000
流式Socket(STREAM):
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;
数据报式Socket(DATAGRAM):
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
端口用来标识计算机里的某个程序。
按端口号可分为3大类
(1) 公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。
通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。
(2) 注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。
也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。
(3) 动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。
理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。
2、Socket一般应用模式(服务器端和客户端)
1.服务端welcoming socket 开始监听端口(负责监听客户端连接信息)
2.客户端client socket连接服务端指定端口(负责接收和发送服务端消息)
3.服务端welcoming socket 监听到客户端连接,创建connection socket。(负责和客户端通信)
服务器端的Socket(至少需要两个)
一个负责接收客户端连接请求(但不负责与客户端通信)
每成功接收到一个客户端的连接便在服务端产生一个对应的负责通信的Socket
在接收到客户端连接时创建.
为每个连接成功的客户端请求在服务端都创建一个对应的Socket(负责和客户端通信).
客户端的Socket
必须指定要连接的服务端地址和端口。
通过创建一个Socket对象来初始化一个到服务器端的TCP连接。
3、Socket的通讯过程
服务器端:
申请一个socket
绑定到一个IP地址和一个端口上
开启侦听,等待接授连接
客户端:
申请一个socket
连接服务器(指明IP地址和端口号)
服务器端接到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通讯,原监听socket继续监听。
4、Socket的构造函数
连接通过构造函数完成。
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
AddressFamily 成员指定 Socket 用来解析地址的寻址方案。例如,InterNetwork 指示当 Socket 使用一个 IP 版本 4 地址连接。
SocketType 定义要打开的 Socket 的类型
Socket 类使用 ProtocolType 枚举向 Windows Sockets API 通知所请求的协议
如:mySocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
AddressFamily.InterNetWork:使用 IP4地址。
SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。
此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。
Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
ProtocolType.Tcp:使用传输控制协议。
注意点:
l 至少要定义一个要连接的远程主机的IP和端口号。
l 端口号必须在 1 和 65535之间,最好在1024以后。
l 要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。
如:
IPAddress addr = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(addr, 10001);
服务端先绑定:serverWelcomeSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
l 一个Socket一次只能连接一台主机。
l Socket关闭后无法再次使用。
l 每个Socket对象只能一台远程主机连接. 如果你想连接到多台远程主机, 你必须创建多个Socket对象。
Socket方法:
------------------相关类--------------------------
IPAddress类:包含了一个IP地址
IPEndPoint类:包含了一对IP地址和端口号
--------------------方法们------------------------------
Socket (): 创建一个Socket
Bind(): 绑定一个本地的IP和端口号(IPEndPoint)
Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量
Connect(): 初始化与另一个Socket的连接
Accept(): 接收连接并返回一个新的socket
Send(): 输出数据到Socket
Receive(): 从Socket中读取数据
Close(): 关闭Socket (销毁连接)
5、Socket通信基本流程图
6、基于TCP的Socket编程
TCP service:可靠的字节流传输
7、Socket源代码:
引用的链接:http://pan.baidu.com/s/1i3EX7lN 密码:d148
本文的链接可以直接下载:源码下载
源码 -- 图示如下
部分代码展示
SocketClient
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace _20151110_SocketClient { public partial class SocketClient : Form { Socket socketSend; public SocketClient() { InitializeComponent(); } #region SocketClient_Load private void SocketClient_Load(object sender, EventArgs e) { //取消跨线程检查操作 Control.CheckForIllegalCrossThreadCalls = false; } #endregion #region btnStartConnect_Click private void btnStartConnect_Click(object sender, EventArgs e) { try { socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint point = new IPEndPoint(IPAddress.Parse(txtIP.Text.Trim()), Convert.ToInt32(txtPort.Text.Trim())); socketSend.Connect(point); ShowMsgSend(string.Format("连接{0}服务器成功!",txtIP.Text.Trim())); Thread th = new Thread(Receive); th.IsBackground = true; th.Start(); //禁用Connect button btnStartConnect.Enabled = false; } catch (Exception) { MessageBox.Show("服务器暂时没有开启,请稍后再试!"); } } #endregion #region btnSendMsg_Click private void btnSendMsg_Click(object sender, EventArgs e) { try { string strMsg = txtMsg.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(strMsg); socketSend.Send(buffer); ShowMsgLocal(string.Format("{0}--{1}:\r\n{2}", "LocalHost", DateTime.Now.ToString(), strMsg)); //清除文本框中的内容 txtMsg.Clear(); } catch (Exception) { } } #endregion #region Receive private void Receive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 5]; int r = socketSend.Receive(buffer); if (r == 0) { break; } string strMsg = Encoding.UTF8.GetString(buffer, 0, r); ShowMsgSend(string.Format("{0}--{1}:\r\n{2}", socketSend.RemoteEndPoint.ToString(), DateTime.Now.ToString(), strMsg)); } } catch (Exception) { } } #endregion #region ShowMsgSend private void ShowMsgSend(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region ShowMsgLocal private void ShowMsgLocal(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region SocketClient_FormClosing private void SocketClient_FormClosing(object sender, FormClosingEventArgs e) { try { socketSend.Close(); } catch (Exception) { } } #endregion } }
SocketServer
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace _20151110_SocketServer { public partial class SocketServer : Form { Socket socketWatch; Socket socketSend; Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>(); public SocketServer() { InitializeComponent(); } #region SocketServer_Load private void SocketServer_Load(object sender, EventArgs e) { //取消跨线程检查 Control.CheckForIllegalCrossThreadCalls = false; } #endregion #region btnStartBind_Click private void btnStartBind_Click(object sender, EventArgs e) { try { socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint point = new IPEndPoint(IPAddress.Parse(txtIP.Text.Trim()), Convert.ToInt32(txtPort.Text.Trim())); socketWatch.Bind(point); ShowMsgSend("监听成功!!!"); socketWatch.Listen(10); //Thread Thread th = new Thread(Accept); th.IsBackground = true; th.Start(socketWatch); //禁用StartBind button btnStartBind.Enabled = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion #region btnSendMsg_Click private void btnSendMsg_Click(object sender, EventArgs e) { try { string strMsg = txtMsg.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(strMsg); string selectedIP = cboUserList.SelectedItem.ToString(); dicSocket[selectedIP].Send(buffer); ShowMsgLocal(string.Format("{0}--{1}:\r\n{2}", "LocalHost", DateTime.Now.ToString(), strMsg)); //清除文本框中的内容 txtMsg.Clear(); } catch (Exception) { } } #endregion #region Accept private void Accept(object socketObj) { try { Socket socketWatch = socketObj as Socket; while (true) { socketSend = socketWatch.Accept(); ShowMsgSend(socketSend.RemoteEndPoint.ToString() + "连接成功"); dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend); cboUserList.Items.Add(socketSend.RemoteEndPoint.ToString()); //设置Combobox的默认值 if (cboUserList.Items.Count > 0) { cboUserList.SelectedIndex = 0; } Thread th = new Thread(Receive); th.IsBackground = true; th.Start(); } } catch (Exception) { } } #endregion #region Receive private void Receive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 5]; int r = socketSend.Receive(buffer); if (r == 0) { break; } string strMsg = Encoding.UTF8.GetString(buffer, 0, r); ShowMsgSend(string.Format("{0}--{1}:\r\n{2}", socketSend.RemoteEndPoint.ToString(), DateTime.Now.ToString(), strMsg)); } } catch (Exception) { } } #endregion #region ShowMsgSend private void ShowMsgSend(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region ShowMsgLocal private void ShowMsgLocal(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion private void SocketServer_FormClosing(object sender, FormClosingEventArgs e) { try { socketSend.Close(); } catch (Exception) { } } } }
本文引自:https://www.cnblogs.com/wt627939556/p/6675247.html