- 上大学的时候一提到TCP 什么的,Socket什么的就发怵,因为那时还不入门,后面慢慢的就还好,本来是没什么想法的,但是凑巧工作中写了一些TCP 通信的例子,所以下班后简单的整理了一下,希望可以帮助到有需要的童鞋。
- 写在前面,写的只是一个demo,里面注释我觉得写的不少了,有问题的欢迎指出或者联系博主。废话不多说了, 直接上代码。
- 效果图
Server端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TCPServer
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
string host;
int port = 8888;//随意啦,0-65535,如果不知道端口有没被占用,打开cmd,输入 netstat -a 即可查看
Socket serverSocket = null;
IPHostEntry hostEntry = null;
Socket tempClient = null;
Task taskOfAccept;
Task taskOfReceive;
public MainWindow()
{
InitializeComponent();
}
private void Start_Click(object sender, RoutedEventArgs e)
{
//This is server start logic
// use the current host name as the default.
host = Dns.GetHostName();
//获取主机信息
hostEntry = Dns.GetHostEntry(host);
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
IPAddress address = hostEntry.AddressList[2];//Get Current pc IP ,注意这里IPV4和IPV6是有区别,WIFI和网线也有区别,这个可以debug的时候看信息,不是1,就是2
IPEndPoint ipe = new IPEndPoint(address, port);
serverSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);//创建使用何种协议的套接字
serverSocket.Bind(ipe);//绑定ip端口,如果不希望指定端口也是可以的
serverSocket.Listen(10);//最多监听10个,如果超过10个,多余的会等待或者超时
listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add(ipe.Address + "Server opened"); }));
taskOfAccept = new Task(AcceptClient);//因为accept是阻塞主线程的,我们最好不让界面阻塞,所以开启一个线程
taskOfAccept.Start();
}
private void AcceptClient()
{
while (true)
{
tempClient = serverSocket.Accept();//不断的监听
listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add( " connected"); }));
ThreadPool.QueueUserWorkItem(new WaitCallback(Receive),tempClient);//开启线程池,执行receive,因为我们希望是一直收发所以,最好也是加上loop
//线程池的优点是可以帮你自动管理执行某段函数,缺点呢是不太好控制,一般使用flag来控制,这里因为是个示意,所以没有加
}
}
private void Receive(object state)
{
while (true)
{
string dataReceive = string.Empty;
Byte[] bytesReceived = new Byte[256];
int bytes = 0;
// The following will block until the page is transmitted.
do
{
bytes = tempClient.Receive(bytesReceived, bytesReceived.Length, 0); //不断地get数据一直到get所有的数据
dataReceive = dataReceive + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Server Received:" + dataReceive); }));
dataReceive = string.Empty;
}
while (bytes > 0); //如果bytes < 0 是退出了一个客户端,这个可以用来检测客户端的生存状态
}
}
private void Send_Click(object sender, RoutedEventArgs e)
{
string dataSend = string.Empty;
dataSend = "hello client";
Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSend);
tempClient.Send(bytesSent, bytesSent.Length, 0); //Send也是同步阻塞的哦
listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Server send:" + dataSend); }));
}
private void Stop_Click(object sender, RoutedEventArgs e)
{
try
{
serverSocket.Shutdown(SocketShutdown.Both); //both指停止收发行为,因为我只写了一个client的支持逻辑,如果想一对多,就需要添加全局list来侦听客户端的生存状态
}
finally
{
serverSocket.Close();
}
}
}
}
Server 端的界面
<Window x:Class="TCPServer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TCPServer" Height="350" Width="525">
<Grid>
<Button Content="Start" HorizontalAlignment="Left" Click="Start_Click" Margin="33,46,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Stop" HorizontalAlignment="Left" Click="Stop_Click" Margin="401,46,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Send" HorizontalAlignment="Left" Click="Send_Click" Margin="216,46,0,0" VerticalAlignment="Top" Width="75"/>
<ListBox Name="listbox" HorizontalAlignment="Left" Height="205" Margin="33,90,0,0" VerticalAlignment="Top" Width="443"/>
</Grid>
</Window>
Client端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TCPClient
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
Socket client = null;
Task taskOfReceiveData;
public MainWindow()
{
InitializeComponent();
}
private void Connect_Click(object sender, RoutedEventArgs e)
{
//Connect
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect("169.254.13.65", 8888); //同步阻塞的哦
if (client.Connected)
{
//Send
listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add("Connect to Server:169.254.13.65"); }));
string dataSent = "hello server";
Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSent);
client.Send(bytesSent, bytesSent.Length, 0);
}
taskOfReceiveData = new Task(receiveData); //一直收
taskOfReceiveData.Start();
}
private void receiveData()
{
while (true)
{
string dataReceive = string.Empty;
Byte[] bytesReceived = new Byte[256];
int bytes = 0;
// The following will block until the page is transmitted.
do
{
bytes = client.Receive(bytesReceived, bytesReceived.Length, 0); //不断地get数据一直到get所有的数据
dataReceive = dataReceive + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Client receive:" + dataReceive); }));
dataReceive = "";
}
while (bytes > 0);
}
}
private void Send_Click(object sender, RoutedEventArgs e)
{
//Send 点一次发一次就行了
string dataSent = "hello server";
Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSent);
client.Send(bytesSent, bytesSent.Length, 0);
listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add("Client send:" + dataSent); }));
}
}
}
Client 界面
<Window x:Class="TCPClient.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TCPClient" Height="350" Width="525">
<Grid>
<Button Content="Connect" Click="Connect_Click" HorizontalAlignment="Left" Margin="50,50,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Send" Click="Send_Click" HorizontalAlignment="Left" Margin="370,50,0,0" VerticalAlignment="Top" Width="75"/>
<ListBox Name="listbox" HorizontalAlignment="Left" Height="190" Margin="50,89,0,0" VerticalAlignment="Top" Width="395"/>
</Grid>
</Window>
有问题直接留言哦。