小妹请教大家一个关于Socket编程的基础问题,盼望得到大家的帮助,谢谢~

emilyxie 2009-03-05 12:09:56
我在做Socket 异步通信的时候,遇到如下问题不知怎么解决,期盼得到大家的帮助:

问题:
我在服务器端如何将多个客户端连接上来的Socket连接信息存储起来,以便服务器要向某一个客户端发送信息的时候可以找到这个客户端的连接信息,还有,服务器找到这些信息后如何如何发送信息给这个客户端呢?
希望有具体的代码加以说明!^_^

在线急盼解决,谢谢~

...全文
209 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
liumj2001 2009-03-11
  • 打赏
  • 举报
回复
一分不给?
wxd024 2009-03-07
  • 打赏
  • 举报
回复
帮顶
weimin19861015 2009-03-07
  • 打赏
  • 举报
回复
是不是女的啊???
liumj2001 2009-03-06
  • 打赏
  • 举报
回复
袄。这时就不能来通过这来进行处理。

可以通过错误捕捉来进行处理。删除这个用户。
jy251 2009-03-06
  • 打赏
  • 举报
回复
认错。。。。

我当时脑袋bu知道怎么想的,onreceive看成委托了。。。。今天早上突然想起来了。。。原来说错了。。。。哈哈···不好意思····

另外,我想知道,如果客户端异常断开怎么办???比如断电了,客户端怎么发送logout给服务端?
sder1985 2009-03-05
  • 打赏
  • 举报
回复
不懂
jy251 2009-03-05
  • 打赏
  • 举报
回复
听你的意思,你是想要建立Client和Server之间的长连接,如果服务端有了数据,便给指定的Client发送数据,对吧。

其实这种模式(长链接)在处理这个问题的时候并不是很好用,因为你需要对连接进行维护,如果Client断开了连接,那么你服务端的Client数组就需要删除这个客户端。
如果你实在要使用长链接也行,这样做,当一个Client连接到Server之后,server可以获取到对方的IP,你就在服务端建立一个多维的数组,让这个数组保存每一个Client的socket对象以及他们的IP,他们的标识。当你需要发送给某个具体的Client的时候,你通过标识来找到对应的socket对象,发送过去。

其实还有两种解决办法:
1.Server如果有了数据,那么发送广播,每一个Client都接收这个广播,广播中添加需要哪个Client来进行处理,每个Client都进行判定,如果是指定的Client,那么就处理。

2.短连接(一般最常用到的),Client每隔一定的时间访问服务端,服务端如果获取数据,那么就将数据保存在服务端本地,并且标注是哪个Client的数据。Client访问服务端的时候,区搜索这些数据,如果有对应的,那么就放给client。
pcjbird 2009-03-05
  • 打赏
  • 举报
回复
/// <summary>
/// 给一个客户提供服务
/// </summary>
private void ServiceClient()
{
Socket client = clientsocket;//赋值给client
bool keepalive = true;

int offset = 0;
int num2 = 0;
int increment = 0;
byte[] buffer = new byte[4];
byte[] buffer2 = new byte[0];
try
{
Client ncl = new Client(client.RemoteEndPoint.ToString(), client.RemoteEndPoint, clientservice, client);
clients.Add(ncl);
NetworkStream ns = new NetworkStream(client, FileAccess.ReadWrite);
while (keepalive && ns != null)
{
if (!client.Connected)
{
Console.WriteLine("客户端断线...");
}
if (ns.DataAvailable)
{
if (increment == 0)
{
offset += ns.Read(buffer, offset, 4 - offset);
if (offset >= 4)
{
increment = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, 0));
num2 = 0;
offset = 0;
if ((increment >= 6 * 1024) || (increment < 0))
{
increment = 0;
}
else if (buffer2.Length < increment)
{
buffer2 = new byte[increment];
}
}
}
else
{
if (num2 < increment)
{
num2 += ns.Read(buffer2, num2, increment - num2);
}
if (num2 == increment)
{
this.OnDataReceived(ns, buffer2, increment);
increment = 0;
}
}
}
if (!ns.DataAvailable)
{
Thread.Sleep(100);
}
}
}
catch (Exception ex)
{
Console.WriteLine("异常:" + ex.Message + "...");
string leaveName = "";
int remove = 0;
bool found = false;
int c = clients.Count;
//从client的ArrayList中查找有没有相符的client
//有的话就作好删掉的准备
for (int n = 0; n < c; n++)
{
Client cl = (Client)clients[n];
if (cl.Host == client.RemoteEndPoint)
{
leaveName = cl.Name;
remove = n;
found = true;
break;
}
}

if (found)
{
Console.WriteLine(leaveName + "离开...");
clients.RemoveAt(remove);//从clients的ArrayList里面删掉要当前要退出的client
client.Close();//关闭套接口
keepalive = false;//keepalive=false则这个线程服务完毕
}
}
}





/// <summary>
/// 发送消息到指定的client
/// </summary>
/// <param name="ns"></param>
/// <param name="writer"></param>
private void SendToClient(NetworkStream ns, byte[] data)
{
try
{
Console.WriteLine("Send to Client...");
BinaryWriter writer = new BinaryWriter(ns);
writer.Write(IPAddress.HostToNetworkOrder(data.Length));
writer.Write(data);
writer.Flush();
}
catch (Exception ex)//如果有异常则退出
{
Console.WriteLine("异常:" + ex.Message + "...");
}
}



///////////////////////////////
Client类是存储客户端信息的类 自己去定义下~~~~~~~~·
liumj2001 2009-03-05
  • 打赏
  • 举报
回复
有看不明白的问问。
liumj2001 2009-03-05
  • 打赏
  • 举报
回复
//发送登陆成功的消息,不发送登陆者
if (clientInfologin.socket != clientSocket)
{
//Send the message to all users
clientInfologin.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(OnSend), clientInfologin.socket);
}
}


break;

case Command.Logout:

//When a user wants to log out of the server then we search for her
//in the list of clients and close the corresponding connection

int nIndex = 0;
foreach (ClientInfo client in clientList)
{
if (client.socket == clientSocket)
{
clientList.RemoveAt(nIndex);
break;
}
++nIndex;
}

clientSocket.Close();

msgToSend = msgReceived;
message = msgToSend.ToByte();
msgToSend.strMessage = "<<<" + msgReceived.strId + "退出系统>>>";
foreach (ClientInfo clientInfomsg in clientList)
{
//发给所有人退出信息
if (msgReceived.strId != clientInfomsg.strID)
{
clientInfomsg.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(OnSend), clientInfomsg.socket);
}

}


break;

case Command.Message:

//Set the text of the message that we will broadcast to all users
msgToSend = msgReceived;
message = msgToSend.ToByte();
foreach (ClientInfo clientInfomsg in clientList)
{
//只发给接受者
if (clientInfomsg.strID == msgToSend.objstrId)
{
//Send the message to all users
clientInfomsg.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(OnSend), clientInfomsg.socket);
}
}

break;

case Command.List:

//同步数据
msgToSend = msgReceived;

//Collect the names of the user in the chat room
foreach (ClientInfo client in clientList)
{
//To keep things simple we use asterisk as the marker to separate the user names
msgToSend.strMessage += client.strID + "*";
}

message = msgToSend.ToByte();

foreach (ClientInfo clientInfolist in clientList)
{
//只发给接受者
if (clientInfolist.strID == msgToSend.strId)
{
//Send the message to all users
clientInfolist.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(OnSend), clientInfolist.socket);
}
}
break;
}

//if (msgToSend.cmdCommand != Command.List || msgToSend.cmdCommand != Command.Chkpws) //List messages are not broadcasted
//{
// message = msgToSend.ToByte();

// foreach (ClientInfo clientInfo in clientList)
// {
// if (clientInfo.socket != clientSocket ||
// msgToSend.cmdCommand != Command.Login)
// {
// //Send the message to all users
// clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
// new AsyncCallback(OnSend), clientInfo.socket);
// }
// }

txtLog.Text += msgToSend.strMessage + "\r\n";
//}


//}
//catch (Exception ex)
//{
// clientSocket.Close();
// MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}

public void OnSend(IAsyncResult ar)
{
//try
//{
Socket client = (Socket)ar.AsyncState;
client.EndSend(ar);
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}
public void OnENDReceive(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
client.EndReceive(ar);
}
}


}
liumj2001 2009-03-05
  • 打赏
  • 举报
回复
private void OnReceive(Data msgReceived, Socket clientSocket)
{
//Socket clientSocket = clsglo.tcpcl.Client;
//try
//{

// clientSocket.EndReceive(ar);

//Transform the array of bytes received from the user into an
//intelligent form of object Data
// Data msgReceived = new Data(byteData);

//We will send this object in response the users request
Data msgToSend = new Data();

byte [] message;

//If the message is to login, logout, or simple text message
//then when send to others the type of the message remains the same

//转换发送与接收消息
msgToSend.strPSW = msgReceived.strPSW;
msgToSend.cmdCommand = msgReceived.cmdCommand;
msgToSend.strName = msgReceived.strName;
msgToSend.strId = msgReceived.strId;

msgToSend.objstrId = msgReceived.objstrId;
msgToSend.objstrip = msgReceived.objstrip;
msgToSend.objstrport = msgReceived.objstrport;


switch (msgReceived.cmdCommand)
{
case Command.Chkpws:




//检测密码是否正确

if (msgReceived.strPSW == "1")
{
msgToSend.strMessage = "pwsok";
}
else
{
msgToSend.strMessage = "pwserr";
}
message = msgToSend.ToByte();
clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);


break;
case Command.Login:

//When a user logs in to the server then we add her to our
//list of clients
msgToSend = msgReceived;
ClientInfo clientInfo = new ClientInfo();
clientInfo.socket = clientSocket;
clientInfo.strID = msgReceived.strId;

clientList.Add(clientInfo);

//Set the text of the message that we will broadcast to all users
msgToSend.strMessage = "<<<" + msgReceived.strId + " 登陆系统>>>";
message = msgToSend.ToByte();
foreach (ClientInfo clientInfologin in clientList)
{
liumj2001 2009-03-05
  • 打赏
  • 举报
回复
ClientInfo就是存储客户信息的。

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace Server
{

public partial class SGSserverForm : Form
{
//The ClientInfo structure holds the required information about every
//client connected to the server
struct ClientInfo
{
public Socket socket; //Socket of the client
public string strID; //Name by which the user logged into the chat room
}

//The collection of all clients logged into the room (an array of type ClientInfo)
ArrayList clientList;

//The main socket on which the server listens to the clients
Socket serverSocket;

byte[] byteData = new byte[1024];
private byte[] recByte;
private SplitBytes sb;
TcpClient atcpcl = new TcpClient();

public SGSserverForm()
{
Control.CheckForIllegalCrossThreadCalls = false;
clientList = new ArrayList();
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

sb = new SplitBytes();
recByte = new byte[1024];
//try
//{
//We are using TCP sockets
serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);

//Assign the any IP of the machine and listen on port number 1000
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 19112);


//clsglo.tcpsrv =new TcpListener(19112);
//clsglo.tcpsrv.Start();
//Bind and listen on the given address
//socket绑定端口
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(4);
//联接对像给SOCKET
//serverSocket = clsglo.tcpsrv.Server;
//联接对像给tcpclist

//serverSocket = clsglo.tcpsrv.AcceptSocket();

//clsglo.tcpcl.Client = serverSocket;

//使用tcp对像进行监听
// AsyncCallback GetStreamMsgCallback = new AsyncCallback(OnAccept);
// clsglo.tcpcl.GetStream().BeginRead(recByte, 0, 1024, GetStreamMsgCallback, null);

//Accept the incoming clients使用socket对像的监听
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, "SGSserverTCP",
// MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}

private void OnAccept(IAsyncResult ar)
{
//try
//{
Socket clientSocket = serverSocket.EndAccept(ar);

//Start listening for more clients
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

//Once the client connects then start receiving the commands from her
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None,
new AsyncCallback(Getmsg), clientSocket);
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, "SGSserverTCP",
// MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}
private void Getmsg(IAsyncResult ar)
{

Socket clientSocket = (Socket)ar.AsyncState;
//Socket clientSocket = serverSocket.EndAccept(ar);


atcpcl = new TcpClient();
atcpcl.Client = clientSocket;
int numberOfBytesRead;
bool isFinish = true;

//try
//{

//lock (clientSocket)
// {
numberOfBytesRead = clientSocket.EndReceive(ar);

if (numberOfBytesRead < 1)
{
//If a value less than 1 received that means that client disconnected
clientSocket.Close();
return;
}
// }

sb.AddBytes(byteData, numberOfBytesRead);
byteData = new byte[1024];

if (clientSocket.Available!=0)
{
isFinish = false;
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(Getmsg), clientSocket);
}

if (isFinish)
{
Data msgReceived = new Data(sb.ReceiveAllByte);
OnReceive(msgReceived, clientSocket);
sb.Dispose();
//clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnENDReceive), clientSocket);




//If the user is logging out then we need not listen from her
//如果客户没有退出则维护消息循环
if (msgReceived.cmdCommand != Command.Logout)
{
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(Getmsg), clientSocket);

}
//if (isLogin)
//{
// lock (clsglo.tcpcl.GetStream())
// {
// AsyncCallback GetStreamMsgCallback = new AsyncCallback(myReadCallBack);
// clsglo.tcpcl.GetStream().BeginRead(recByte, 0, 1024, GetStreamMsgCallback, null);
// }
//}
}
//}
//catch (Exception ex)
//{

// clsglo.tcpcl.Close();
//}
//try
//{
// Socket clientSocket = serverSocket.EndAccept(ar);

// //Start listening for more clients
// serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

// //Once the client connects then start receiving the commands from her
// clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None,
// new AsyncCallback(OnReceive), clientSocket);

//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, "SGSserverTCP",
// MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}

beargo 2009-03-05
  • 打赏
  • 举报
回复
不知道你用的是TCP还是UDP呢
huweiwo 2009-03-05
  • 打赏
  • 举报
回复
帮顶
qq603284891 2009-03-05
  • 打赏
  • 举报
回复
我赖学知识的!学完走人! - -!
wxz280973534 2009-03-05
  • 打赏
  • 举报
回复
啊 小妹啊?
女的,稀有,一定要帮顶
homejiji 2009-03-05
  • 打赏
  • 举报
回复
说个简单的方法。。。

tcp在连接之后可以获得客户端的ip地址和端口号如192.168.0.2:5555因为这样的连接具有唯一性所以把它作为Dictionary的key
然后将它存入
Dictionary<string, Socket> m_DTSockets = new Dictionary<string, Socket>();//key 是ip地址和端口号组成的字符串

操作'
在服务端与客户端连接上的时候就把ip地址和端口号和对应的socket对象存入Dictionary中

在服务端与客户端断开的时候将对应的数据从Dictionary中删除

需要送信的时候从Dictionary中获得指定的socket去操作就可以

emilyxie 2009-03-05
  • 打赏
  • 举报
回复
对不起~ 邮箱写错了,是lhbing@126.com

[Quote=引用 18 楼 emilyxie 的回复:]
嘿嘿,发一份给我吧~ lihongbing@126.com

引用 16 楼 liumj2001 的回复:
如果要判断异常退出,论坛里有很多列子。

不贴代码了。谁要,我发代码给他好了。
[/Quote]
emilyxie 2009-03-05
  • 打赏
  • 举报
回复
嘿嘿,发一份给我吧~ lihongbing@126.com

[Quote=引用 16 楼 liumj2001 的回复:]
如果要判断异常退出,论坛里有很多列子。

不贴代码了。谁要,我发代码给他好了。
[/Quote]
liumj2001 2009-03-05
  • 打赏
  • 举报
回复
不过建议采用我代码里说的这种异步传输模式,比较简单,如果数据压力不大可以通过SERVER来转发。也不需要打洞。

加载更多回复(4)

111,126

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧