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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 大虾挂了 中级黑马   /  2013-10-19 13:50  /  1661 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 大虾挂了 于 2013-10-21 12:47 编辑

先分享一下我的方法。下面是服务端的代码,颜色字体部分为服务端接收客户端发送数据的相关部分
后面附件会补上所有的程序
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace 窗体
{
    /// <summary>
    /// 服务端接收客户端信息时,该结构体作为接收线程中委托的参数
    /// key用于标识当前通信套接字的远程IP和端口
    /// sao即是当前与客户端进行通信的套接字
    /// </summary>
    public struct temp
    {
        public  string key;
        public  Socket sao;
    }
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        Socket socketWatch = null;
        Dictionary<string,Socket> dic=new Dictionary<string,Socket>();
        Dictionary<string, Thread> threaddic = new Dictionary<string, Thread>();
        private void begin_Click(object sender, EventArgs e)
        {
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress address = IPAddress.Parse(textIp.Text.Trim());
            IPEndPoint jiedian = new IPEndPoint(address, int.Parse(textPoint.Text.Trim()));
            socketWatch.Bind(jiedian);
            socketWatch.Listen(10);
            Thread threadWatch = new Thread(connect);
            threadWatch.IsBackground = true;
            threadWatch.Start();
        }
        public void connect()
        {
            while (true)
            {
                Socket socketConnection = socketWatch.Accept();
                //将负责通信的套接字放在dic字典里,远程IP和端口作为键
                dic.Add(socketConnection.RemoteEndPoint.ToString(),socketConnection);
                //将远程IP和端口放入列表中
                lbOnline.Items.Add(socketConnection.RemoteEndPoint.ToString());
                //信息提示哪个客户端连接成功
                ShowMsg(socketConnection.RemoteEndPoint.ToString()+"连接成功");
               //每次有一个新的客户端接入,就为其准备一个线程,将这个线程放入threaddic字典里,远程IP和端口作为键
                threaddic.Add(socketConnection.RemoteEndPoint.ToString(), new Thread(MsgReceive));
                //将作为委托参数的结构体初始化
                temp tp = new temp() {key=socketConnection.RemoteEndPoint.ToString(),sao=socketConnection };
                threaddic[socketConnection.RemoteEndPoint.ToString()].IsBackground = true;
                //接收对应客户端信息的线程开始运行
                threaddic[socketConnection.RemoteEndPoint.ToString()].Start(tp);
            }
        }
        public void MsgReceive(Object o)
        {

            //将传入的参数转化为temp结构体,存入mid中
            temp mid = (temp)o;
            while (true)
            {
                byte[] MsgReceive = new byte[1024];

                //调用对应套接字(mid.sao)的Receive方法
                int length = mid.sao.Receive(MsgReceive);
                string strMsg = System.Text.Encoding.UTF8.GetString(MsgReceive, 0, length);
                textMsg.AppendText("接受了" +"\""+ strMsg+"\""+"从"+mid.key+"\n");
            }
        }
        public void ShowMsg(string a)
        {
            textMsg.AppendText( a + "\r\n");
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            byte[] MsgSend = System.Text.Encoding.UTF8.GetBytes(textSend.Text.Trim());
            dic[lbOnline.Text].Send(MsgSend);
            textMsg.AppendText("发送了" + "\""+textSend.Text.Trim()+"\"" + "给" + lbOnline.Text+"\n");        }
        }
}

客户端的代码就不发了
贴几张效果图好了


1.JPG (76.71 KB, 下载次数: 43)

服务端开启,两个客户端开始连接

服务端开启,两个客户端开始连接

2.JPG (78.92 KB, 下载次数: 46)

服务端分别向两个客户端发送信息

服务端分别向两个客户端发送信息

3.JPG (79.61 KB, 下载次数: 48)

客户端轮流向服务端发送信息

客户端轮流向服务端发送信息

客户端和服务端.rar

105.52 KB, 下载次数: 115

评分

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

查看全部评分

8 个回复

倒序浏览
这里我的方法比较麻烦,结构体都用上了,而且线程里面还套了线程,感觉略坑,调试的时候,服务端和客户端一旦开始连接,随便关一个都报异常,到现在都不知道怎么解决。
客户端关闭了的话服务端报什么异常啊!!!!!
回复 使用道具 举报
使用 try{} catch{}捕捉异常。显示在MSG 里
回复 使用道具 举报
在聊天室视频里  有异常处理的这一篇  你可以仔细看看

这个错误是因为
//调用对应套接字(mid.sao)的Receive方法
                int length = mid.sao.Receive(MsgReceive);
这一段一直再循环接收客户发来的信息   所以当你随便关一个的时候就会报错
回复 使用道具 举报
用try catch 处理异常就OK了,
回复 使用道具 举报
ィSlick 发表于 2013-10-19 15:59
在聊天室视频里  有异常处理的这一篇  你可以仔细看看

这个错误是因为

貌似懂了,刚发现我下的视频少很多
回复 使用道具 举报
haxyek 金牌黑马 2013-10-20 10:16:17
7#
视频里面用的是字典,你用的机构体也很正常。
视频的顺序是不是看的有错误?所以你会感觉少东西。聊天这个是先看6.IP那个
回复 使用道具 举报
haxyek 发表于 2013-10-20 10:16
视频里面用的是字典,你用的机构体也很正常。
视频的顺序是不是看的有错误?所以你会感觉少东西。聊天这个 ...

是。。。。我看少了,视频太多了,我放的又太乱,后来才找到后面的部分,现在知道上面的问题了。还好,主体思想和我感觉差不多,我开始还以为我弄的太麻烦了呢,我用结构体是为了传2个参数过去,我想让服务端知道这个消息是谁发来的。对于线程,我也是保存在了一个字典里,也是用远程ip和端口作为键
回复 使用道具 举报
视频看少了,这个贴子就这样了结了吧,我都懂了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马