r); ShowMsg(socketSend.RemoteEndPoint.ToString() + “:” + st

时间:2021-07-08 07:20:12

客户端要连接处事器:首先要知道处事器的IP地点。而处事器里有很多的应用措施,每一个应用措施对应一个端标语

所以客户端想要与处事器中的某个应用措施进行通信就必需要知道阿谁应用措施的地址处事器的IP地点,及应用措施所对应的端标语


TCP协议:

安适不变,一般不会产生数据丢掉,但是效率低。操作TCP产生数据一般颠末3次握手(所有效率低,本身百度三次握手)


UDP协议:

快速,效率高,但是不不变,容易产生数据丢掉(没有颠末三次握手,不管处事器有空没空,信息全往处事器发,所有效率搞,但处事器忙的时候就没步伐措置惩罚惩罚你的数据,容易造成数据丢掉,不不变)


代码如下:

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.Sockets;

using System.Net;

using System.Threading;

namespace Socket通信

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

this.txtPort.Text = “5000”;

this.txtIp.Text = “192.168.137.1”;

}

private void btnStart_Click(object sender, EventArgs e)

{

//当点击开始监听的时候,在处事器端创建一个卖力监听IP地点跟端标语的Socket

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

//Any:供给一个 IP 地点,指示处事器应侦听所有网络接口上的客户端勾当。此字段为只读。

IPAddress ip = IPAddress.Any;

//创建端标语东西;将txtPort.Text控件的值设为处事真个端标语

IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));

//监听

socketWatch.Bind(point);

ShowMsg(“监听告成”);

socketWatch.Listen(10);//连接行列队伍的最大长度 ;即:一个时间点内最大能让几个客户端连接进来,赶过长度就进行排队

//期待客户端连接;Accept()这个要领能接收客户真个连接,,并为新连接创建一个卖力通信的Socket

Thread th = new Thread(Listen); //被线程执行的要领如果有参数的话,参数必需是object类型

Control.CheckForIllegalCrossThreadCalls = false; //因为.net不允许跨线程访谒的,所以这里打消跨线程的查抄。.net不查抄是否有跨线程访谒了,所有就不会报: “从不是创建控件“txtLog”的线程访谒它” 这个错误了,从而实现了跨线程访谒

th.IsBackground = true; //将th这个线程设为后台线程。

//Start(object parameter); parameter:一个东西,包罗线程执行的要领要使用的数据,即线程执行Listen要领,Listen的参数

th.Start(socketWatch);  //这个括号里的参数其实是Listen()要领的参数。因为Thread th = new Thread(Listen)这个括号里只能写要领名(函数名) 但是Listen()要领是有参数的,所有就要用Start()要领将它的参数添加进来

}

/// <summary>

/// 期待客户端连接,如果监控到有客户端连接进来就创建一个与之通信的Socket

/// </summary>

/// <param name=”o”></param>

void Listen(object o) //这里为什么不直接通报Socket类型的参数呢? 原因是:被线程执行的要领如果有参数的话,参数必需是object类型

{

Socket socketWatch = o as Socket;

while (true) //为什么这里要有个while循环?因为当一小我私家连接进来的时候创建了与之通信的Socket后就措施就会往下执行了,就不会再回来为第二小我私家的连接创建卖力通信的Socket了。(应该是每小我私家(每个客户端)创建一个与之通信的Socket)所以要写在循环里。

{

//期待客户端连接;Accept()这个要领能接收客户真个连接,并为新连接创建一个卖力通信的Socket

Socket socketSend = socketWatch.Accept();

dic.Add(socketSend.RemoteEndPoint.ToString(), socketSend); //(按照客户真个IP地点和端标语找卖力通信的Socket,每个客户端对应一个卖力通信的Socket),ip地点及端标语作为键,将卖力通信的Socket作为值填充到dic键值对中。

//我们通过卖力通信的这个socketSend东西的一个RemoteEndPoint属性,能够拿到长途连过来的客户真个Ip地点跟端标语

ShowMsg(socketSend.RemoteEndPoint.ToString() + “:” + “连接告成”);//效果:192.168.1.32:连接告成

comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString()); //将连接过来的每个客户端都添加到combBox控件中。

//客户端连接告成后,处事器应该接收客户端发来的动静。

Thread getdata = new Thread(GetData);

getdata.IsBackground = true;

getdata.Start(socketSend);

}

}

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

/// <summary>

/// 不竭的接收客户端发送过来的动静

/// </summary>

/// <param name=”o”></param>

void GetData(object o)

{

while (true)

{

Socket socketSend = o as Socket;

//将客户端发过来的数据先放到一个字节数组里面去

byte[] buffer = new byte[1024 * 1024 * 2]; //创建一个字节数组,字节数组的长度为2M

//实际接收到的有效字节数; (操作Receive要领接收客户端传过来的数据,然后把数据生存到buffer字节数组中,返回一个接收到的数据的长度)

int r = socketSend.Receive(buffer);

if (r == 0) //如果接收到的有效字节数为0 说明客户端已经*了。这时候就跳出循环了。

{

//只有客户端给用户动员静,不成能是发0个长度的字节。即便发空动静,空动静也是有过个长度的。所有接收到的有效字节长度为0就代表客户端已经*了

break;

}

//将buffer这个字节数组里面的数据凭据UTF8的编码,解码成我们能够读懂的的string类型,因为buffer这个数组的实际存储数据的长度是r个 ,所以从索引为0的字节开始解码,总共解码r个字节长度。

string str = Encoding.UTF8.GetString(buffer, 0, r);

ShowMsg(socketSend.RemoteEndPoint.ToString() + “:” + str);

}

}

private void ShowMsg(string str)

{

txtLog.AppendText(str + “\r\n”); //将str这个字符串添加到txtLog这个文本框中。

}

/// <summary>

/// 处事端给客户端发信息

/// </summary>

/// <param name=”sender”></param>

/// <param name=”e”></param>

private void btnSend_Click_1(object sender, EventArgs e)

{

if (comboBox1.SelectedItem == null) //如果comboBox控件没有选中值。就提示用户选择客户端

{

MessageBox.Show(“请选择客户端”);

return;

}

string str = txtMes.Text; //获取用户输入的内容 (处事端要给客户端发的信息)

byte[] strByte = Encoding.Default.GetBytes(str); //将信息转换成二进制字节数组

string getIp = comboBox1.SelectedItem as string; //comboBox存储的是客户真个(ip+端标语)

Socket socketSend = dic[getIp] as Socket; //按照这个(ip及端标语)去dic键值对中找对应 赋值与客户端通信的Socket【每个客户端都有一个卖力与之通信的Socket】

socketSend.Send(strByte); //将信息发送到客户端

}

}

}

开打开始命令  cmd   telnet 10.18.16.46 5000    即telnet 处事器ip地点  绑定的端标语