二话不说,大家先看一下我服务端添加的引用
using
System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using commands;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using commands;
注意一下,这里的最后一个引用commands,与客户端的commands必须是同一个dll,同样的代码编译出来的文件都不行。这是为什么
捏。试想一下,你用一个规则去序列化一个对象,然后用另一个规则进行反序列化,得到的对象不会是原来的对象了吧。
好,下一步。这里是服务器端,每一个客户端连到服务器,都对应一个类的对象,然后把它们搞到一个列表里面。这样就方便进行操作了。在这个基础上,给客户端
发信息,或者转发一个客户端的信息给另一个或多个客户端,都是小case了。
下面就是客户端对应的类了。
public
class
InConnectUser
{
public TcpClient client { get ; set ; }
public BinaryReader br { get ; set ; }
public BinaryWriter bw { get ; set ; }
public Guid InUseID { get ; set ; }
public bool IfUserLogin = false ;
public Entity.FeeRules obj_enFeeRules = new Entity.FeeRules();
public Entity.InUse obj_enInUse = new Entity.InUse();
public Entity.Computer obj_enComputer = new Entity.Computer();
public Entity.User obj_enUser = new Entity.User();
public InConnectUser(TcpClient client)
{
this .client = client;
NetworkStream networkstream = client.GetStream();
br = new BinaryReader(networkstream);
bw = new BinaryWriter(networkstream);
}
public void Close()
{
br.Close();
bw.Close();
client.Close();
}
}
{
public TcpClient client { get ; set ; }
public BinaryReader br { get ; set ; }
public BinaryWriter bw { get ; set ; }
public Guid InUseID { get ; set ; }
public bool IfUserLogin = false ;
public Entity.FeeRules obj_enFeeRules = new Entity.FeeRules();
public Entity.InUse obj_enInUse = new Entity.InUse();
public Entity.Computer obj_enComputer = new Entity.Computer();
public Entity.User obj_enUser = new Entity.User();
public InConnectUser(TcpClient client)
{
this .client = client;
NetworkStream networkstream = client.GetStream();
br = new BinaryReader(networkstream);
bw = new BinaryWriter(networkstream);
}
public void Close()
{
br.Close();
bw.Close();
client.Close();
}
}
我这里是和网吧管理相关的,所以加了很多逻辑方面的东西在里面就不贴出来占篇幅了。大家如果把代码copy过去发现出错,就注释掉吧。
话不多,看到关键的地方都写在下面的注释里面。
//
在线用户列表
private List < TcpHelper.InConnectUser > onlineUserList = new List < TcpHelper.InConnectUser > ();
IPAddress localAddress;
private const int port = 51888 ;
private TcpListener myListener;
// 开启服务器的按钮
private void button_StartServer_Click( object sender, EventArgs e)
{
myListener = new TcpListener(localAddress, port);
myListener.Start();
label_status.Text = " 开启 " ;
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
// timer1.Enabled = true;
button_StartServer.Visible = false ;
button_StopServer.Visible = true ;
}
// 关闭服务器的按钮
private void button_StopServer_Click( object sender, EventArgs e)
{
label_status.Text = " 关闭 " ;
// 关闭服务器,移除list的用户。
// for (int i = onlineUserList.Count - 1; i >= 0; i--)
// {
// RemoveOnlineUser(onlineUserList[i]);
// }
myListener.Stop();
button_StartServer.Visible = true ;
button_StopServer.Visible = false ;
}
/// <summary>
/// 监听连接
/// </summary>
private void ListenClientConnect()
{
TcpClient newClient = null ;
while ( true )
{
try
{
// 停在此处监听连接,如果有新客户端连接就运行下去
newClient = myListener.AcceptTcpClient();
}
catch (Exception)
{
break ;
}
InConnectUser user = new InConnectUser(newClient);
Thread threadReceive = new Thread(ReceiveData);
threadReceive.Start(user);
onlineUserList.Add(user);
}
}
/// <summary>
/// 收消息
/// </summary>
/// <param name="UserState"></param>
private void ReceiveData( object UserState)
{
InConnectUser user = (InConnectUser)UserState;
TcpClient client = user.client;
MessageInfo receiveObject;
while ( true )
{
try
{
byte [] bytes = new byte [ 999 ];
// 停在此处,networkstream流中有新数据则读出
int i = user.br.Read(bytes, 0 , 999 );
MemoryStream memory = new MemoryStream(bytes);
BinaryFormatter format = new BinaryFormatter();
receiveObject = (MessageInfo)format.Deserialize(memory);
}
catch (Exception)
{
return ;
}
switch (receiveObject.CommandsTypes)
{
case CommandsTypes.RequestHowLong:
// 这里是我处理各种命令的方法,和这个博客的主题无关,就不贴出来了。
// 处理好之后,就在这个方法里面发送回应给对应的客户端,所以一定要有参数user
// ManagerHowLong(user);
break ;
case CommandsTypes.RequestUserLogin:
// ManagerUserLogin(user, receiveObject);
break ;
case CommandsTypes.RequestUserlogout:
// ManagerUserLogout(user);
break ;
case CommandsTypes.RequestLogout:
// 注意这里是return,本意是如果客户端的连接要关闭, 就用跳出循环
// 但是我的是网吧管理,不考虑这种情况,所以就未做处理
return ;
case CommandsTypes.RequestModPWD:
// ManagerModPWD(user, receiveObject);
break ;
case CommandsTypes.RequestMachineLogin:
// ManagerMachineLogin(user, receiveObject);
break ;
case CommandsTypes.RequestTalk:
// ManagerTalk(receiveObject);
break ;
default :
break ;
}
}
}
/// <summary>
/// 发消息
/// </summary>
/// <param name="user"> 发给谁 </param>
/// <param name="userSend"> 发送内容 </param>
private void SendToClient(TcpHelper.InConnectUser user, MessageInfo userSend)
{
try
{
MemoryStream memory = new MemoryStream();
BinaryFormatter format = new BinaryFormatter();
format.Serialize(memory, userSend);
byte [] bytes = memory.ToArray();
user.bw.Write(bytes);
user.bw.Flush();
}
catch (Exception)
{
// 发送失败
}
}
private List < TcpHelper.InConnectUser > onlineUserList = new List < TcpHelper.InConnectUser > ();
IPAddress localAddress;
private const int port = 51888 ;
private TcpListener myListener;
// 开启服务器的按钮
private void button_StartServer_Click( object sender, EventArgs e)
{
myListener = new TcpListener(localAddress, port);
myListener.Start();
label_status.Text = " 开启 " ;
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
// timer1.Enabled = true;
button_StartServer.Visible = false ;
button_StopServer.Visible = true ;
}
// 关闭服务器的按钮
private void button_StopServer_Click( object sender, EventArgs e)
{
label_status.Text = " 关闭 " ;
// 关闭服务器,移除list的用户。
// for (int i = onlineUserList.Count - 1; i >= 0; i--)
// {
// RemoveOnlineUser(onlineUserList[i]);
// }
myListener.Stop();
button_StartServer.Visible = true ;
button_StopServer.Visible = false ;
}
/// <summary>
/// 监听连接
/// </summary>
private void ListenClientConnect()
{
TcpClient newClient = null ;
while ( true )
{
try
{
// 停在此处监听连接,如果有新客户端连接就运行下去
newClient = myListener.AcceptTcpClient();
}
catch (Exception)
{
break ;
}
InConnectUser user = new InConnectUser(newClient);
Thread threadReceive = new Thread(ReceiveData);
threadReceive.Start(user);
onlineUserList.Add(user);
}
}
/// <summary>
/// 收消息
/// </summary>
/// <param name="UserState"></param>
private void ReceiveData( object UserState)
{
InConnectUser user = (InConnectUser)UserState;
TcpClient client = user.client;
MessageInfo receiveObject;
while ( true )
{
try
{
byte [] bytes = new byte [ 999 ];
// 停在此处,networkstream流中有新数据则读出
int i = user.br.Read(bytes, 0 , 999 );
MemoryStream memory = new MemoryStream(bytes);
BinaryFormatter format = new BinaryFormatter();
receiveObject = (MessageInfo)format.Deserialize(memory);
}
catch (Exception)
{
return ;
}
switch (receiveObject.CommandsTypes)
{
case CommandsTypes.RequestHowLong:
// 这里是我处理各种命令的方法,和这个博客的主题无关,就不贴出来了。
// 处理好之后,就在这个方法里面发送回应给对应的客户端,所以一定要有参数user
// ManagerHowLong(user);
break ;
case CommandsTypes.RequestUserLogin:
// ManagerUserLogin(user, receiveObject);
break ;
case CommandsTypes.RequestUserlogout:
// ManagerUserLogout(user);
break ;
case CommandsTypes.RequestLogout:
// 注意这里是return,本意是如果客户端的连接要关闭, 就用跳出循环
// 但是我的是网吧管理,不考虑这种情况,所以就未做处理
return ;
case CommandsTypes.RequestModPWD:
// ManagerModPWD(user, receiveObject);
break ;
case CommandsTypes.RequestMachineLogin:
// ManagerMachineLogin(user, receiveObject);
break ;
case CommandsTypes.RequestTalk:
// ManagerTalk(receiveObject);
break ;
default :
break ;
}
}
}
/// <summary>
/// 发消息
/// </summary>
/// <param name="user"> 发给谁 </param>
/// <param name="userSend"> 发送内容 </param>
private void SendToClient(TcpHelper.InConnectUser user, MessageInfo userSend)
{
try
{
MemoryStream memory = new MemoryStream();
BinaryFormatter format = new BinaryFormatter();
format.Serialize(memory, userSend);
byte [] bytes = memory.ToArray();
user.bw.Write(bytes);
user.bw.Flush();
}
catch (Exception)
{
// 发送失败
}
}
代码不多,但是也要花点小时间去看看条理才会清晰。
龙弟弟奉献,转载请注明出处谢谢。
另外我这里有根据这个做成的小聊天程序,大家如果有需要可以找我。
http://files.cnblogs.com/salty/tcp.rar