前言
Socket 是对 TCP/IP 协议的封装,Socket 只是个接口不是协议,通过 Socket 我们才能使用 TCP/IP 协议,除了 TCP,也可以使用 UDP 协议来传递数据。
本文不对TCP/IP进行深入理解阐释,仅仅针对WinForm中如何使用Socket的几个关键点进行阐述。
Server
采用的是C/S架构,在某一时刻,服务器只能与一个客户端建立连接。
1、初始化,将本地IP作为Server的IP地址,端口号可以随意指定。
public ServerForm()
{
InitializeComponent();
IPAddress[] localIP = Dns.GetHostAddresses(Dns.GetHostName()); //Get any IP
foreach (IPAddress address in localIP)
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
tb_IPAdress.Text = address.ToString();
}
}
}
2、创建监听实例,启动Server
private void StartServer_button_Click(object sender, EventArgs e)
{
new System.Threading.Thread(s =>
{
try
{
TcpListener listener = new TcpListener(IPAddress.Any, int.Parse(textBox5.Text));
listener.Start();
client = listener.AcceptTcpClient();
strRead = new StreamReader(client.GetStream());
strWrite = new StreamWriter(client.GetStream());
strWrite.AutoFlush = true;
Listen_backgroundWorker.RunWorkerAsync(); //Start recieving data
Listen_backgroundWorker.WorkerSupportsCancellation = true;
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
})
{ IsBackground = true }.Start();
}
如代码所示,新建了一个线程——线程启动了一个指定IP地址和端口号的服务端,并开始监听读写请求。如下的Listen_backgroundWorker线程,则对接收到的消息在UI上进行显示:
private void Listen_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected)
{
try
{
recieve = strRead.ReadLine();
this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("C发送 : " + recieve + "\n"); }));
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
3、Server向已与之建立连接的Client发送消息:
private void Send_button_Click(object sender, EventArgs e)
{
if (SendtextBox.Text != "")
{
textToSend = SendtextBox.Text;
Send_backgroundWorker.RunWorkerAsync();
}
SendtextBox.Text = "";
}
private void Send_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected)
{
strWrite.WriteLine(textToSend);
this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("S发送 : " + textToSend + "\n"); }));
}
else
{
MessageBox.Show("Send Failed!");
}
Send_backgroundWorker.CancelAsync();
}
Client
1、将Client连接至指定IP地址和端口号Server。
private void ConnectToServer_button_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient();
IPEndPoint ip_End = new IPEndPoint(IPAddress.Parse(textBox6.Text), int.Parse(textBox4.Text));
client.Connect(ip_End);
if (client.Connected)
{
Receive_textBox.AppendText("Connected to server" + "\n");
stw = new StreamWriter(client.GetStream());
str = new StreamReader(client.GetStream());
stw.AutoFlush = true;
Receive_backgroundWorker.RunWorkerAsync();
}
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
如下代码,在Client连接的到Server之后,也开始可以随时接收由Server传来的消息:
private void Receive_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected)
{
try
{
recieve = str.ReadLine();
this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("S发送 : " + recieve + "\n"); }));
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
2、与Server建立连接的Client可以随时发送消息:
private void Send_button_Click(object sender, EventArgs e)
{
if (Send_textBox.Text != "")
{
textToSend = Send_textBox.Text;
Send_backgroundWorker.RunWorkerAsync();
}
Send_textBox.Text = "";
}
private void Send_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected)
{
stw.WriteLine(textToSend);
this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("C发送 : " + textToSend + "\n"); }));
}
else
{
MessageBox.Show("Send Failed!");
}
Send_backgroundWorker.CancelAsync();
}
运行结果:
源码:https://github.com/Deskew/SocketChat