Socket通信实例详解

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();
}

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值