A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 qiumanlover 于 2013-5-29 13:48 编辑

服务端和客户端是一样的程序,即只有一个程序,开两个,绑定不同地址,然后实现通讯。
发送消息是通过监听TextBox的KeyDown事件实现的,接收消息是放在线程里的
现在的问题是:两边的程序只能接受一次对方的消息,此后就收不到了
如果将接受消息的方法放在按键事件里,则会卡住输入框,直到收到对面的消息
源码如下:
  1. using System;
  2. using System.Text;
  3. using System.Windows.Forms;
  4. using System.Net.Sockets;
  5. using System.Net;
  6. using System.Threading;

  7. namespace UDP_SYN
  8. {
  9.         public partial class UDPClient : Form
  10.         {
  11.                 private IPEndPoint localIpe = null;                                //本地节点
  12.                 private Socket localSock = null;                                //绑定本地节点的套接字
  13.                 private static IPEndPoint remoteIpe = null;                //远程结点
  14.                 private EndPoint Remote = null;                                        //用于接收消息的抽象对象结点
  15.                 private byte[] sendbuff = new byte[1024];                //发送缓冲区
  16.                 private byte[] recvbuff = new byte[1024];                //接收缓冲区
  17.                 private int msgLen;                                                                //接收的数据的字节长度

  18.                 public UDPClient()
  19.                 {
  20.                         CheckForIllegalCrossThreadCalls = false;
  21.                         InitializeComponent();
  22.                         TextBox.CheckForIllegalCrossThreadCalls = false;        //关闭文本框的跨线程检查
  23.                 }

  24.                 private void Form1_Load(object sender, EventArgs e)
  25.                 {
  26.                         button1.Enabled = true;
  27.                         txtSend.Enabled = false;
  28.                 }

  29.                 private void button1_Click(object sender, EventArgs e)
  30.                 {
  31.                         localIpe = new IPEndPoint(IPAddress.Parse(txtLocalIP.Text.ToString().Trim()),
  32.                                 Convert.ToInt32(txtLocalPort.Text.ToString().Trim()));
  33.                         localSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  34.                         remoteIpe = new IPEndPoint(IPAddress.Parse(txtRemoteIP.Text.ToString().Trim()),
  35.                                 Convert.ToInt32(txtRemotePort.Text.ToString().Trim()));

  36.                         localSock.Bind(localIpe);

  37.                         Thread startThrd = new Thread(new ThreadStart(RecvThrd));
  38.                         startThrd.IsBackground = true;
  39.                         startThrd.Start();

  40.                         //处理按键之后的页面布局,阻止修改配置
  41.                         txtSend.Enabled = true;
  42.                         button1.Enabled = false;
  43.                         txtLocalIP.Enabled = false;
  44.                         txtLocalPort.Enabled = false;
  45.                         txtRemoteIP.Enabled = false;
  46.                         txtRemotePort.Enabled = false;
  47.                         txtSend.Focus();

  48.                 }

  49.                 //按下回车键发送消息,并显示在自己的接收消息窗口
  50.                 private void txtSend_KeyDown(object sender, KeyEventArgs e)
  51.                 {
  52.                         if (e.KeyCode == Keys.Enter)
  53.                         {
  54.                                 try
  55.                                 {
  56.                                         sendbuff = Encoding.ASCII.GetBytes(txtSend.Text.ToString());
  57.                                         localSock.SendTo(sendbuff, remoteIpe);
  58.                                         txtRecv.AppendText(localSock.LocalEndPoint.ToString() + "  " +
  59.                                                 DateTime.Now.ToString() + "  " + remoteIpe.ToString()
  60.                                                 + "\r\n\t" + txtSend.Text.ToString() + "\r\n");
  61.                                         SendKeys.Send("{BackSpace}");
  62.                                         txtSend.Clear();
  63.                                 }
  64.                                 catch (Exception ex)
  65.                                 {
  66.                                         MessageBox.Show(ex.ToString());
  67.                                 }
  68.                         }
  69.                 }

  70.                 //接收消息的方法,放入线程,防止阻塞当前窗口
  71.                 private void RecvThrd()
  72.                 {
  73.                         Remote = (EndPoint)(remoteIpe);
  74.                         msgLen = localSock.ReceiveFrom(recvbuff, ref Remote);
  75.                         Remote = (EndPoint)(remoteIpe);
  76.                         ShowMsg(Encoding.ASCII.GetString(recvbuff, 0, msgLen));

  77.                 }

  78.                 public void ShowMsg(string str)
  79.                 {
  80.                         txtRecv.AppendText(Remote.ToString() + "  " + DateTime.Now.ToString()
  81.                                 + "  " + Remote.ToString() + "\r\n\t" + str + "\r\n");
  82.                 }
  83.         }
  84. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

3 个回复

倒序浏览
先沙发......
回复 使用道具 举报
要想持续监听接受消息,就必须调用新的线程来专门负责监听发来的消息,可以参考我都代码解析:

服务端namespace 客户端连接
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false; //关闭跨线程调用         
        }
        Thread watchthread=null;//j将监听套接字定义在类中,方便调用
        Dictionary<string,Socket> dict=new Dictionary<string,Socket>();
        // 定义字典链表,来存储申请连接用户的IP和端口即套接字信息
        Dictionary<string, Socket> dictrec = new Dictionary<string, Socket>();
        //定义字典列表,用来存连接客户端的套接字
       Socket socketWatch=null;

        private void protbtn_Click(object sender, EventArgs e)
        {   //创建服务端的监听套接字,参数(使用 的IP寻址协议,使用流式连接,使用TCP协议传输数据)
              socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
           // 获取文本框的IP地址对象。
            IPAddress address = IPAddress.Parse(iptxt.Text.Trim());
            //创建含有IP和port的网络节点对象
            IPEndPoint endpoint=new IPEndPoint(address,int.Parse(prottxt.Text.Trim()));
            //将负责监听的套接字绑定到唯一的IP端口上
            socketWatch.Bind(endpoint);
            //设置监听队列的长度
            socketWatch.Listen(10);
            //
            watchthread = new Thread(WTC);
            //给线程委托
            watchthread.IsBackground = true;
             //绑定后台线程
            watchthread.Start();
             //线程开始

        }

        private void showMsg(string p)
        {
            txtb1.AppendText(p+"\r\n");
        }

        void WTC()
        {
            while (true)//持续监听
            {

                 Socket socketconnecttion = socketWatch.Accept();//一旦监听到了请求,返回新的通讯的docket。
                //将新生成的IP和端口信息和socket加入到字典的键和值
                dict.Add(socketconnecttion.RemoteEndPoint.ToString(),socketconnecttion);
                //将连接的客户端IP加入到控件的列表
                onlinelist.Items.Add(socketconnecttion.RemoteEndPoint.ToString());
                //将远程客户端计算机的IP和端口 添加到onlinelist列表  
                Thread recThread = new Thread(Rec);               
               //与客户端建立连接后,持续监听客户端是否发送信息,有新的线程来监听
                recThread.IsBackground = true;//后台
                recThread.Start(socketconnecttion);//传参,当前生成的socket
                showMsg("客户端连接成功!"+socketconnecttion.RemoteEndPoint.ToString()+"\r\n");

            }
        }

        void Rec(object socketconnet)
        {

            while (true)//持续接收客户端消息
            {
                Socket socketconnettion = socketconnet as Socket;//强制转换成socket
               
                byte[] arrmsg = new byte[1024 * 1024 * 2];
               //定义2M字节序列 ,来接受 用户消息
                int length;

                length = socketconnettion.Receive(arrmsg);
                //接受客户端的消息

                if (arrmsg[0] == 0)//判断客户端发来的是文字还是文件 0是文字 1是文件
                {

                    string str = System.Text.Encoding.UTF8.GetString(arrmsg, 1, length);
                     //将字节序列转换成字符串
                    showMsg("客户端--->" + str);
                }
                else
                    if (arrmsg[0] == 1)//当接受是文件时
                    {
                        SaveFileDialog sfd = new SaveFileDialog();
                        //实例化保存文件对话框
                        if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                       //当保存成功, 将文件名赋给变量filesavepath
                        {
                            string filesavepath = sfd.FileName;
                            using (FileStream fs = new FileStream(filesavepath, FileMode.Create))//(文件路径,文件模式)
                            //文件流很占内存,所以用using及时释放
                            {
                                fs.Write(arrmsg, 1, length - 1);
                                showMsg("文件保存成功!"+filesavepath);

                            }
                        }
                    }
            }

        }

        private void btnsend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(onlinelist.Text))
            {
                MessageBox.Show("请先选择一个好友");
                return;
            }
            else
            {
                string str = txtserver.Text.Trim();
                //将要发送的字符串转换成utf8对应的字节数组
                byte[] arrmsg = System.Text.Encoding.UTF8.GetBytes(str);
                string strclientKey = onlinelist.Text;
                //通过 键 查询 值(即客户的套接字) 来调用值的send()来发送信息
                dict[strclientKey].Send(arrmsg);
                //socketconnecttion.Send(arrmsg);
                showMsg("服务端:--->" + str + "\r\n");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        { //服务端发送信息
            string str = txtserver.Text.Trim();

            byte[] byarr = new byte[1024 * 1024 * 2];

            byarr = System.Text.Encoding.UTF8.GetBytes(str);
            //将字符串转换成字节序列

            foreach (Socket s in dict.Values)
            { //遍历群发
                s.Send(byarr);

            }

            showMsg("群发完毕");
        }


    }
}
————————————————————————————————
客户端:
  private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }
        Socket socketclient = null;
        Thread recThread = null;
        private void protbtn_Click(object sender, EventArgs e)
        {
            IPAddress address = IPAddress.Parse(iptxt.Text.Trim());
            //从文本框获取IP
            IPEndPoint endpoint=new IPEndPoint( address,int.Parse(prottxt.Text.Trim()));
            //从文本框获取端口或IP
            socketclient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //连接服务器
            socketclient.Connect(endpoint);
            //调用线程
            recThread = new Thread(RecMsg);
            recThread.IsBackground = true;
            recThread.Start();


        }

        void RecMsg()
        {
            while (true)
            {
                //定义一个接受用的缓存区(2M字节)
                byte[] arrmsgrec = new byte[1024 * 1024 * 2];
                //将接受到的消息数据传入arrmsgrec数组,并返回真正接受数据的长度
                int length=socketclient.Receive(arrmsgrec);
                //将字节序列转化为字符串然(要转换的字节序列,开始位置,转换长度)
                string strMsgRec = System.Text.Encoding.UTF8.GetString(arrmsgrec, 0, length);
                ShowMsg("服务端-->"+strMsgRec);

            }


        }
        void ShowMsg(string str)
        {
            //想文本框追加文本
            txtb1.AppendText( str + "\r\n");
        }

        private void btnsend_Click(object sender, EventArgs e)
        {//客户端向服务端发送信息。
            string str = txtclient.Text.Trim();
            byte[] byArr = new byte[1024 * 1024 * 2];
            byArr = System.Text.Encoding.UTF8.GetBytes(str);
            byte[] byarrsend = new byte[byArr.Length + 1];
            byarrsend[0] = 0;//发送文字,字节序列首位赋0;
            Buffer.BlockCopy(byArr,0,byarrsend,1,byArr.Length);

            socketclient.Send(byarrsend);//发送字符序列
            ShowMsg("客户端--->"+str);
        }

        private void filechoosebtn_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();//打开文件选择对话框

            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)//判断是否选择文件
            {
                filepathtxt.Text = ofd.FileName;//在文本框显示文件路径
            }
        }

        private void filesendbtn_Click(object sender, EventArgs e)
        { //发送文件
            using (FileStream fs = new FileStream(filepathtxt.Text, FileMode.Open))
            {
                byte[] arrfile = new byte[1024 * 1024 * 2];
                int length = fs.Read(arrfile, 0, arrfile.Length);
                byte[] arrsend=new byte[length+1];
                arrsend[0] = 1;//第一个为标识为
                Buffer.BlockCopy(arrfile,0,arrsend,1,length);
                socketclient.Send(arrsend);
            }
        }
    }

}

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 赞一个!

查看全部评分

回复 使用道具 举报
大家加油   以后有事情   或者没加分 给我留言或者看我的个性签名
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马