Socket通信可实现服务器和客户端进行通信,通过socket来实现监听/接收/发送。(所有代码为测试成功)
依据通信步骤实现通信。
服务器端界面以及代码:
服务器端开始监听的通信步骤:
1.创建一个用于监听连接的Socket对象
2.指定端口号和服务器的ip建立一个EndPoint对象
3.用socket对象的Bind()方法绑定EndPoint
4.用socket对象的Listen()方法开始监听
5.接收到客户端的连接,用socket的Accept()方法创建一个用于和客户端进行通信的Socket对象
6.通信结束后,关闭socket
//定义回调:解决跨线程访问控件问题
private delegate void SetTextValueCallBack(string strValue);
private SetTextValueCallBack setCallBack;
//定义接收客户端发送消息的回调
private delegate void ReceiveMsgCallBack(string strReceive);
private ReceiveMsgCallBack receiveMsgCallBack;
//定义回调给Combobox控件添加元素
private delegate void SetCmbCallBack(string item);
private SetCmbCallBack setCmbCallBack;
//定义发送文件的回调
private delegate void SendFileCallBack(byte[] bf);
private SendFileCallBack sendCallBack;
//用于通信的Socket
Socket socketSend;
//用于监听的Socket
Socket socketWatch;
//将远程连接的客户端IP地址和Socket存入集合中
Dictionary<string,Socket> dicSocket=new Dictionary<string,Socket>();
//创建用于监听连接的线程
Thread AcceptSocketThread;
//接收客户端发送消息的线程
Thread threadReceive;
public Server()
{
InitializeComponent();
}
//开始监听
private void btnStartListen_Click(object sender,EventArgs e)
{
//当点击开始监听的时候,在服务器端创建一个负责监听IP地址和端口号的Socket
socketWatch=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//获取IP地址,这里的ip和端口号为服务器的,所有的客户端都要和服务器的这个端口号连接
IPAddress ip=IPAddress.Parse(txtIP.Text.Trim());
//创建端口号
IPEndPoint point=new IPEndPoint(ip,Convert.ToInt32(txtPort.Text.Trim()));
//监听的socket绑定IP地址和端口号
socketWatch.Bind(point);
txtInforLog.AppendText("监听成功"+Environment.NewLine);
//开始监听,设置最大可以同时连接多少和请求
socketWatch.Listen(10);
//实例化回调
setCallBack=new SetTextValueCallBack(SetTextValue);
receiveMsgCallBack=new ReceiveMsgCallBack(ReceiveMsg);
setCmbCallBack=new SetCmbCallBack(AddCmbItem);
sendCallBack=new SendFileCallBack(SendFile);
//创建开始监听的线程
AcceptSocketThread=new Thread(new ParameterizedThreadStart(StartListen));
AcceptSocketThread.IsBackground=true;
AcceptSocketThread.Start(socketWatch);
}
//等待客户端的连接,并且创建与之通信的Socket
private void StartListen(object obj)
{
Socket socketWathch=obj as Socket;
while(true)
{
//等待客户端的连接,并且创建一个用于通信的Socket,这里如果没有客户端的连接会阻塞
socketSend=socketWatch.Accept();
//获取远程主机的ip地址和端口号(strIp的格式:127.0.0.1:8887)
string strIP=socketSend.RemoteEndPoint.ToString();
dicSocket.Add(strIP,socketSend);
cmbClient.Invoke(setCmbCallBack,strIP);
string strMsg="远程主机:"+socketSend.RemoteEndPoint+"连接成功";
//使用回调
txtConnectLog.Invoke(setCallBack,strMsg);
//定义接收客户端消息的线程
Thread threadReceive=new Thread(new ParameterizedThreadStart(Receive));
threadReceive.IsBackground=true;
threadReceive.Start(socketSend);
}
}
//服务器端不停接收客户端发送的消息
private void Receive(object obj)
{
Socket socketSend=obj as Socket;
while(true)
{
//客户端连接成功后,服务器接收客户端发送的消息
byte[] buffer=new byte[2048];
//实际接收的有效字节数
int count=socketSend.Receive(buffer);
//count==0表示客户端关闭,退出循环
if(count==0)
{
break;
}
else
{
string str=Encoding.Default.GetString(buffer,0,count);
string strReceiveMsg="接收:"+socketSend.RemoteEndPoint+" 发送的消息:"+str;
txtInforLog.Invoke(receiveMsgCallBack,strReceiveMsg);
}
}
}
//回调委托需要执行的方法
private void SetTextValue(string strValue)
{
txtInforLog.AppendText(strValue+Environment.NewLine);
}
private void ReceiveMsg(string strReceive)
{
txtInforLog.AppendText(strReceive+Environment.NewLine);
}
private void AddCmbItem(string item)
{
cmbClient.Items.Add(item);
}
//服务器给客户端发送消息
private void btnSendInfor_Click(object sender,EventArgs e)
{
string str=txtMsg.Text.Trim();
byte[] buffer=Encoding.Default.GetBytes(str);
List<byte> list=new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转换为数组
byte[] newBuffer=list.ToArray();
//获得用户选择的ip地址
string ip=cmbClient.SelectedItem.ToString();
dicSocket[ip].Send(newBuffer);
}
//选择需要发送的文件
private void btnChooseFile_Click(object sender,EventArgs e)
{
OpenFileDialog dia=new OpenFileDialog();
//设置初始目录
dia.InitialDirectory=@"";
dia.Title="请选择要发送的文件";
//过滤文件类型
dia.Filter="所有文件|*.*";
dia.ShowDialog();
//将选择的文件的路径赋值给文本框
txtMsg.Text=dia.FileName;
}
//发送文件
private void btnSendFile_Click(object sender,EventArgs e)
{
List<byte> list=new List<byte>();
//获取要发送的文件的路径
string strPath=txtMsg.Text.Trim();
using(FileStream sw=new FileStream(strPath,FileMode.Open,FileAccess.Read))
{
byte[] buffer=new byte[2048];
int r=sw.Read(buffer,0,buffer.Length);
list.Add(1);
list.AddRange(buffer);
byte[] newBuffer=list.ToArray();
btnSendFile.Invoke(sendCallBack,newBuffer);
}
}
//向指定的客户端发送流
private void SendFile(byte[] bf)
{
dicSocket[cmbClient.SelectedItem.ToString()].Send(bf,SocketFlags.None);
}
//停止监听
private void btnStopListen_Click(object send,EventArgs e)
{
socketWatch.Close();
socketSend.Close();
AcceptSocketThread.Abort();
threadReceive.Abort();
}
2.客户端:
客户端开始监听的通信步骤:
1.建立一个socket对象
2.用指定的端口号和服务器的IP建立一个EndPoint对象
3.用socket对象的Connect()方法以上面 的EndPoint对象作为参数,向服务器发出连接请求
4.如果连接成功,就用socket()对象的Send()方法向服务器发送信息
5.用socket对象的Receive()方法接收服务器发来的信息
6.通信结束后关闭Socket
//定义回调
private delegate void SetTextCallBack(string strValue);
private SetTextCallBack setCallBack;
//定义接收服务器端发送消息的回调
private delegate void ReceiveMsgCallBack(string strMsg);
private ReceiveMsgCallBack receiveCallBack;
//创建连接的Socket
Socket socketSend;
//创建接收客户端发送消息的线程
Thread threadReceive;
//连接服务器
private void btnConnect_Click(object sender,EventArgs e)
{
socketSend=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPAddress ip=IPAddress.Parse(txtIP.Text.Trim());
socketSend.Connect(ip,Convert.ToInt32(txtPort.Text.Trim()));
//实例化回调
setCallBack=new SetTextCallBack(setValue);
receiveCallBack=new ReceiveMsgCallBack(setValue);
txtReceiveInfor.Invoke(setCallBack,"连接成功");
//开启一个新的线程
threadReceive=new Thread(new ThreadStart(Receive));
//设置线程中可打开弹框
threadReceive.SetApartmentState(ApartmentState.STA);
threadReceive.IsBackground=true;
threadReceive.Start();
}
//接收来自服务器的信息
private void Receive ()
{
while(true)
{
byte[] buffer=new byte[2048];
//实际接收的字节数
int r=socketSend.Receive(buffer);
if(r==0)
{
break;
}
else
{
//判定接收到的服务器的数据类型
if(buffer[0]==0)
{
string str=Encoding.Default.GetString(buffer,1,r-1);
txtReceiveInfor.Invoke(receiveCallBack,"接收远程服务器:"+socketSend.RemoteEndPoint+"发送的消息:"+str);
}
else if(buffer[0]==1)
{
SaveFileDialog sfd=new SaveFileDialog ();
sfd.InitialDirectory=@"";
sfd.Title="请选择要保存的文件";
sfd.Filter="所有文件|*.*";
sfd.ShowDialog(this);
string strPath=sfd.FileName;
using(FileStream fs=new FileStream(strPath,FileMode.OpenOrCreate,FileAccess.Write))
{
fs.Write(buffer,1,r-1);
}
MessageBox.Show("保存文件成功!");
}
}
}
}
//显示当前接收的服务器的信息
private void setValue(string strValue)
{
txtReceiveInfor.AppendText(strValue+Environment.NewLine);
}
//客户端给服务器发送消息
private void btnSendInfor_Click(object sender,EventArgs e)
{
string strMsg=txtSendInfor.Text.Trim();
byte[] buffer=new byte[2048];
buffer=Encoding.Default.GetBytes(strMsg);
int receive=socketSend.Send(buffer);
}
//断开连接
private void btnDisConnect_Click(object sender,EventArgs e)
{
//关闭Socket
socketSend.Close();
//终止线程
threadReceive.Abort();
}