Wcf tcp
我们利用wcf和tcp做一个qq实时在线聊天
步骤:1:上线和我们的下线功能
2:指定的聊天
3:发送文件和字体颜色
Wcf和tcp的转换:
改配置文件:
我们用控制器启动我们的wcf服务。
` 创建一个主机 绑定我们的服务ServiceHost 用typeof 绑定我们的服务
我们还要写一个事件 就是当通信对象转换到打开的时候我们发生的事件 是为了我们方便知道是否打开了我们的服务器
Opened
然后打开我们的主机 open();
例子:
staticvoid Main(string[] args)
{
using (ServiceHost sh = new ServiceHost(typeof(Service1)))
//这里我们要注意using{}这个方法会销毁我们的程序
//实列化一个服务器 绑定一个接口typeof(接口)
{
sh.Opened += sh_Opened;
//打开
sh.Open();
//暂停不让服务销毁
Console.ReadLine();
}
}
static void sh_Opened(object sender, EventArgs e)
{
Console.WriteLine("服务已经启动;");
}
让一个服务器有回调方法:
后台:在接口中设置回调协定的类型 CallbackContract =typeof(回调类)
回调类中需要返回答复消息 就要设置IsOneWay=true
前台:用服务点出我们的服务主机 ,如果我们的主机有回调我们要服务实例化我们的回调类 InstanceContext
回调类:我们要实现我们服务的回调 如果我们要传值的话我们重构传值
例子:
后台:
接口
[ServiceContract(CallbackContract=typeof(IQQlogin_callback))]
回调接口
[OperationContract(IsOneWay = true)]
void onlines(users user);
前台:
//这里我们把本页面给传入过去
InstanceContext ic = new InstanceContext(new callback_QQ(this));
// QQ_Service是我们的服务名称
QQ_Service.QQloginServiceClient lsqq = new QQ_Service.QQloginServiceClient(ic);
回调类:
public class callback_QQ : QQ_ .IQQloginServiceCallback
{
public QQ _qq;
public callback_QQ(QQ qq)
{
this._qq = qq;
}
public void onlines(QQ_Service.users user)
{
}
public void offlines(string QQ_numer)
{
}
public void sendmess_callback(QQ_Service.DTO_xiaoxi xiaoxi)
{
}
}
1:上线和下线
思路:用户登录访问数据库,登录成功就记录我们用户和用户通道,
在用我们的回调函数告诉前面登录的人,我们上线了
我们用DTO来存储数 :一个登陆返回信息 ,一个记录我们信息和通道的,用一个键值对来取出我们对应的通道,一个上线的对象
登陆返回的DTO:
public class DTO_QQ_reuslt<T>
{
public int number { get; set; }
public string message { get; set; }
//这个泛型用来记录我们在线的人信息
public T value { get; set; }
}
具体思路就是:我们一个用户一登录 我们就记录他的信息和回调通道 和上线信息
然后在调用我们的上线的回调通道
注意我们这里:就是传值的问题
InstanceContext ic = new InstanceContext(new callback_QQ(this));
这里我们传入了一个本页到我们的回调类
所以以后的传值问题我们都传到我们,这页 然后再传入到我们 的回调类
例子:服务:
public DTO.DTO_QQ_reuslt<DTO_uers> getlogin(string name, string password)
{
dbEntities db = new dbEntities();
//得到当前的回调函数
IQQlogin_callback callback = OperationContext.Current.GetCallbackChannel<IQQlogin_callback>();
//获取当前线程正在关闭的事件
OperationContext.Current.Channel.Closing += Channel_Closing;
//返回的信息
DTO.DTO_QQ_reuslt<DTO_uers> result = new DTO.DTO_QQ_reuslt<DTO_uers>();
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(password))
{
result.number = 501;
result.message = "账号或者密码为空";
}
users user = db.users.Where(a => a.user_name == name && a.user_password == password).FirstOrDefault();
if (user != null)
{
_number = name;
//得到我们在线人信息
DTO_uers dto = new DTO_uers();
dto.user = user;
dto.online = DTO.DTO_chuanshu.dpdic.Values.Select(a => a.qqusers).ToList();
//记录通道
DTO_QQreacd qqreacd = new DTO_QQreacd();
qqreacd.qqusers = user;
qqreacd.qqcallback = callback;
result.number = 200;
result.message = "登陆成功";
result.value = dto;
//告诉前面的用户我已经登录了
foreach (var item in DTO.DTO_chuanshu.dpdic.Values)
{
item.qqcallback.onlines(user);
}
//记录用户信息和用户的通道
DTO.DTO_chuanshu.dpdic.Add(name, qqreacd);
}
else
{
result.number = 201;
result.message = "账号或者密码错误";
}
//IQQlogin_callback iqqcallback =OperationContext.Current.GetCallbackChannel<IQQlogin_callback>();
iqqcallback.login(DTO.DTO_chuanshu.qquers);
return result;
}
void Channel_Closing(object sender, EventArgs e)
{
//先移除自己的qq帐号
DTO_chuanshu.dpdic.Remove(_number);
//传递一个下线的qq帐号
foreach (var item in DTO.DTO_chuanshu.dpdic.Values)
{
item.qqcallback.offlines(_number);
}
}
发送信息 就和我们的登陆差不多,调用我们的回调通道
我们发送文件和我们的颜色:
发送文件我们用二进制读取,颜色的话我们用ToArgb()把颜色转换成我们的int 类型 然后我们在回调类中用FromArgb()把它弄回来
例子:客户端
public async void send_File()
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog();
// MessageBox.Show(ofd.FileName);
if (string.IsNullOrEmpty(ofd.FileName))
{
MessageBox.Show("请选择文件");
return;
}
FileStream fs = new FileStream(ofd.FileName, FileMode.Open);
long alllength = fs.Length;
var offset = 0; //记录位置
byte[] filebyte = null;
this.progressBar1.Maximum = (int)(fs.Length / 1000);
while (offset != fs.Length)
{
///这里我们做一个限速传入
if (fs.Length - offset <= 1024 * 100)
{
filebyte = new byte[fs.Length - offset];
}
else
{
filebyte = new byte[1024 * 100];
}
//filebyte = new byte[alllength - offset];
fs.Read(filebyte, 0, filebyte.Length);
sfns = new Send_FileName_Service.Send_FilenameClient();
await sfns.sendfilenameAsync(ofd.SafeFileName, filebyte);
if (jingcheng==0)
{
offset = offset + filebyte.Length;
}
if (jingcheng==-1)
{
offset = 0;
}
this.progressBar1.Value = (offset / 1000);
}
MessageBox.Show(ofd.FileName + "文件传输完成......");
}
服务:
public void sendfilename(string filename,byte[] bytes)
{
string path = "e:/" + filename;
fs = new FileStream(path, FileMode.Append);
fs.Write(bytes,0,bytes.Length);
fs.Close();
}
小技巧:如何让一个对象中装入另外一个对象 我们用泛型
键值对中也可以用上我们的linp语句