互联网通过 IP 定位电脑。
IP地址:
在电脑中通过 Port 来定位程序。
常用端口:21FTP, 25SMTP, 110POP3, 80HTTP, 443HTTPS
程序之间通过 协议 定义通信数据的格式。
网卡接受到数据以后,根据端口号,把数据发送给不同的程序。
是一种通信机制,用于描述IP地址和port,是一个通信链的句柄。用于两个程序的通信。
Socket类似打电话。电话通信的双方相当于相互通信的2个程序,电话号码是IP。用户通话前,首先要占有一部电话(socket),同时要知道对方的号码(对方有一个固定的socket),然后拨号(发出连接请求)。对方假如在场并空闲,拿起电话筒,双方就可以通话(连接成功)。双方通话的过程,相当于一方向socket发送数据,一方从socket接收数据。通话结束后,一方挂起电话,相当于关闭socket,撤销连接,
流式Socket(Stream):是一种面向连接的Socket,tcp协议用stream socket,安全,效率低。
browser和server之间使用的tcp协议(流式socket)
数据报Socket(Datagram):无连接的Socket,udp使用报式Socket,不安全(丢失,顺序混乱,在接收端要分析重排序,要求重发等),效率高。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//服务器段 监听socket
Socket sListen = null;
private void btnListen_Click(object sender, EventArgs e)
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定端口
//2.1获取网络节点(IPEndPoint)对象
IPAddress ip = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
//2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
sListen.Bind(endPoint);
//2.3设置监听队列
//The maximum length of the pending connections queue. : 10
sListen.Listen(10);
//2.4 开始监听,block直到有连接请求,返回值 : A Socket for a newly created connection.
sListen.Accept();
}
程序运行起来以后,accept方法阻塞了当前线程,窗口不能再拖动。
//服务器段 监听socket
Socket sListen = null;
//监听线程
Thread threadListen = null;
private void btnListen_Click(object sender, EventArgs e)
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定端口
//2.1获取网络节点(IPEndPoint)对象
IPAddress ip = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
//2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
sListen.Bind(endPoint);
//2.3设置监听队列
//The maximum length of the pending connections queue. : 10
sListen.Listen(10);
////2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//sListen.Accept();
threadListen = new Thread(ListenConnection);
threadListen.IsBackground = true;
threadListen.Start();
}
private void ListenConnection() {
sListen.Accept();
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
//服务器段 监听socket
Socket sListen = null;
//监听线程
Thread threadListen = null;
private void btnListen_Click(object sender, EventArgs e)
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定端口
//2.1获取网络节点(IPEndPoint)对象
IPAddress ip = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
//2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
sListen.Bind(endPoint);
//2.3设置监听队列
//The maximum length of the pending connections queue. : 10
sListen.Listen(10);
////2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//sListen.Accept();
threadListen = new Thread(ListenConnection);
threadListen.IsBackground = true;
threadListen.Start();
ShowMsg("server initialized");
}
private void ListenConnection() {
sListen.Accept();
ShowMsg("one client connected");
}
private void ShowMsg(String str) {
txtMsg.AppendText(str + "\n");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket socClient = null;
private void btnConnectServer_Click(object sender, EventArgs e)
{
socClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获得要连接的 server 节点
IPAddress ipServer = IPAddress.Parse(txtIP.Text);
IPEndPoint endpoint = new IPEndPoint(ipServer, int.Parse(txtPort.Text));
//向Server发出连接请求
socClient.Connect(endpoint);
}
}
测试:先运行服务器端,start listen,然后客户端project右键,debug,start new instance。连接server。
Server端:
private void ListenConnection() {
//2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//返回通信socket,这个socket 监听 客户端 传来的消息
Socket socMsg = sListen.Accept();
ShowMsg("one client connected");
//3 通信socket 监听client发来的消息
//3.1 消息buffer
byte[] buffer = new byte[1024*1024*1];//1M
//3.2 接收client send方法发来的消息,并存放到buffer中
//Receive方法也会block当前线程,直到接收到client send方法发来的消息
socMsg.Receive(buffer);
//3.3 将接收到的byte数组转成字符串
string strMsg = System.Text.Encoding.UTF8.GetString(buffer);
//3.4 将str显示到textbox
ShowMsg(strMsg);
}
Client端:
private void btnSendMsg_Click(object sender, EventArgs e)
{
string strMsg = txtMsg.Text.Trim();
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
socClient.Send(arrMsg);
}
上面的程序,server端只receive一次client端send来的消息。
private void ListenConnection() {
//2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//返回通信socket,这个socket 监听 客户端 传来的消息
Socket socMsg = sListen.Accept();
ShowMsg("one client connected");
// 2.5 建立通信线程
Thread threadMsg = new Thread(ReceiveMsg);
threadMsg.IsBackground = true;
threadMsg.Start(socMsg);
}
bool isReceive = true;
private void ReceiveMsg(object obj) {
Socket socMsg = obj as Socket;
//3 通信socket 监听client发来的消息
//3.1 消息buffer
byte[] buffer = new byte[1024 * 1024 * 1];//1M
//3.2 接收client send方法发来的消息,并存放到buffer中
//Receive方法也会block当前线程,直到接收到client send方法发来的消息
while (isReceive) {
socMsg.Receive(buffer);
//3.3 将接收到的byte数组转成字符串
string strMsg = System.Text.Encoding.UTF8.GetString(buffer);
//3.4 将str显示到textbox
ShowMsg(strMsg);
}
}
Dictionary dictCon = new Dictionary();
private void ListenConnection() {
//2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//返回通信socket,这个socket 监听 客户端 传来的消息
Socket socMsg = sListen.Accept();
//将当前连接上的client的ip和port,保存到Dictionary中,并显示到listbox中。
listBoxClient.Items.Add(socMsg.RemoteEndPoint.ToString());
dictCon.Add(socMsg.RemoteEndPoint.ToString(), socMsg);
ShowMsg("one client connected");
// 2.5 建立通信线程
Thread threadMsg = new Thread(ReceiveMsg);
threadMsg.IsBackground = true;
threadMsg.Start(socMsg);
}
private void btnSendMsg_Click(object sender, EventArgs e)
{
string endpointStr = null;
if (listBoxClient.SelectedItem != null) {
endpointStr = listBoxClient.SelectedItem.ToString();
if (dictCon.ContainsKey(endpointStr))
{
Socket sClient = dictCon[endpointStr];
//使用 指定 socket将 字符串 发送到 指定的client
sClient.Send(System.Text.Encoding.UTF8.GetBytes(txtInput.Text.Trim() +"\n"));
ShowMsg("to " + endpointStr + " : " + txtInput.Text.Trim());
txtInput.Text = string.Empty;
}
}
}
在client端:接受服务器发来的msg
Thread threadMsg = null;
private void btnConnectServer_Click(object sender, EventArgs e)
{
socClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获得要连接的 server 节点
IPAddress ipServer = IPAddress.Parse(txtIP.Text);
IPEndPoint endpoint = new IPEndPoint(ipServer, int.Parse(txtPort.Text));
//向Server发出连接请求
socClient.Connect(endpoint);
ShowMsg("connected to server");
threadMsg = new Thread(ReceiveMsg);
threadMsg.IsBackground = true;
threadMsg.Start();
}
bool isReceive = true;
private void ReceiveMsg() {
//3 通信socket 监听client发来的消息
//3.1 消息buffer
byte[] buffer = new byte[1024 * 1024 * 1];//1M
//3.2 接收client send方法发来的消息,并存放到buffer中
//Receive方法也会block当前线程,直到接收到client send方法发来的消息
while (isReceive) {
socClient.Receive(buffer);
//3.3 将接收到的byte数组转成字符串
string strMsg = System.Text.Encoding.UTF8.GetString(buffer);
//3.4 将str显示到textbox
ShowMsg("From Server : " + strMsg);
}
}
Dictionary dictCon = new Dictionary();
bool isWatch = true;
private void ListenConnection() {
//2.4 开始监听,block知道有连接请求,返回值 : A Socket for a newly created connection.
//返回通信socket,这个socket 监听 客户端 传来的消息
while(isWatch){
Socket socMsg = sListen.Accept();
//将当前连接上的client的ip和port,保存到Dictionary中,并显示到listbox中。
listBoxClient.Items.Add(socMsg.RemoteEndPoint.ToString());
dictCon.Add(socMsg.RemoteEndPoint.ToString(), socMsg);
ShowMsg("one client connected");
// 2.5 建立通信线程
Thread threadMsg = new Thread(ReceiveMsg);
threadMsg.IsBackground = true;
threadMsg.Start(socMsg);
}
}
Server端: