读书人

C#大牛!在 socket通信中多客户端与

发布时间: 2013-07-20 11:07:48 作者: rapoo

求助C#大牛!!在 socket通信中,多客户端与一个服务器端异步通信时,服务器监听客户端套接字后,如何分别开启一个线程去进行数据传送??
小弟新人,初来报道,求各位大神指导~~

最近在做一个课设,是有关C#中socket异步通信的,要求两台以上客户端向服务器端请求传送图片和视频信息,服务器端在接到请求后分别向每个客户端发送它们需要的信息,在调试过程中,发现一对一的话可以实现基本功能,但只要多客户端的话,另一台倒是显示“已连接”,但请求后得不到回复。故猜测:是在服务器端监听并产生新线程这段代码出问题,没有把两个服务器请求区分开,即没有产生新的套接字去建立通信连接。

但只是个人臆测,还望c#大牛指导~~
现贴上我们主机端和客户端代码,请各位大牛们不吝赐教~~

server端:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using Shell32;
using AviFile;

namespace media
{
public partial class Show : Form
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
Thread serverThread;
Thread clientThread;
Socket serverSocket;
Socket clientSocket;

public Show()
{
InitializeComponent();
}


private Thread threadWatch = null;//负责监听客户端连接请求的线程


private Socket socketWatch = null;//负责监听的套接字

private void ServerStart()
{
IPEndPoint localipep = new IPEndPoint(IPAddress.Any, 6000);

serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//将所创建的套接字与IPEndPoint绑定
serverSocket.Bind(localipep);



serverSocket.Listen(20);
threadWatch = new Thread(WatchConnection);
threadWatch.IsBackground = true;
threadWatch.Start();
}

void WatchConnection()
{

while (true)
{
try
{
allDone.Reset();
serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket);

allDone.WaitOne();
}
catch (Exception ex)
{
MessageBox.Show("listening Error: " + ex.Message);
}
}

}

//接收连接的回调函数
void Accept(IAsyncResult iar)
{
//调用EndAccept完成BeginAccept异步调用,返回一个新的Socket处理与客户的通信
Socket MyServer = (Socket)iar.AsyncState;
clientSocket = MyServer.EndAccept(iar);


//线程挂起

clientThread = new Thread(new ThreadStart(ReceiveData));
clientThread.IsBackground = true;
clientThread.Start();

}
}
解释:ReceiveData()是代码中实现数据传递的代码,原理是根据客户端发来的请求字符串的不同,应用switch case语句执行不同的功能,一对一可以实现的话因该不是这里的问题了~~

client端代码:
using System;
using System.IO;
using System.Drawing;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Client
{
public partial class Form1 : Form
{
public int i = 0;
private Socket client;
private int serverport = 6000;
private IPEndPoint serverEP = null;

public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)//读取ip并连接server端
{
if (textBox1.Text.Trim() == "")
{
textBox1.Select();
return;
}

var exp = @"^([1-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$";

Match m = Regex.Match(textBox1.Text.Trim(), exp);


if (!m.Success)
{
MessageBox.Show("IP地址格式错误!IP地址的格式为xxx.xxx.xxx.xxx(xxx为0-255)。",
"提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
textBox1.SelectAll();
textBox1.Select();
return;
}

ConnectServer(textBox1.Text.Trim());
}


private void ConnectServer(string serverIP)
{
serverEP = new IPEndPoint(IPAddress.Parse(serverIP), serverport);

Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

client.BeginConnect(serverEP, new AsyncCallback(ConnectCallback), client);
}


private void ConnectCallback(IAsyncResult iar)
{
client = (Socket)iar.AsyncState;
try
{
client.EndConnect(iar);
PrintStatus("已连接至服务器。");
PrintStatus("recerving...");

BeginReceive();
}
catch (Exception err)


{
PrintStatus(err.Message);
return;
}
}
解释:BeginReceive()是开始接受数据的函数,PrintStatus()是显示信息的函数。



以上是我们socket通信的主客端代码,请赐教~~
[解决办法]
Server:

socket.beginAccept(...,new AsyncCallBack(OnAccept),..); //异步侦听socket连入

private void OnAccept(IAsyncResult ar)
{
Socket s = socket.EndAccept(ar);
s.beginReceive(...,new AsyncCallBack(OnReceive),s); //异步接收数据
}

private void OnReceive(IasyncResult ar)
{
// 处理数据
}

每连入一个客户端socket 就会BeginReceive
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

每一个Socket连接后,服务端要把

//调用EndAccept完成BeginAccept异步调用,返回一个新的Socket处理与客户的通信
Socket MyServer = (Socket)iar.AsyncState;
clientSocket = MyServer.EndAccept(iar);
这个的 clientSocket 保存到一个列表中。 以后所有像客户端发送Socket都由这个列表中取出对应的对像发送,这样才能向指定的客户端发送信息

你要列子
http://beetle.henryfan.net/ 这个做的很不错了服务端客户端都很全,粘包处理也解决了。开源的。


你好!您说的这个貌似跟我们要求的有点出入。感觉您说的这个像是多人聊天系统,先确定对象再发内容,我们要求服务器端在监听之后就是“死”的了,只有客户端能做决定,而主机要根据客户端的决定智能的实现他们各自的要求。

感觉有点不太一样。。。不知道我说的对吗。。


你的理解是错的。这跟多人聊天系统没关系的,

你所说的客户端相当于,
Client1发送信息 ->服务端接收 ->服务端返回信息给Client1
Client2发送信息 ->服务端接收 ->服务端返回信息给Client2

Client1与Client2是没有关系的是这样子吧

好比两个Client同时发送信息了但服务端返回信息时要返回给哪个客户端。你如何区分出来。


怎么把他们要的结果返回给对应的客户端。看你上面的代码写的你是没法确定的。
所以我所说的要把Socket保存下来就是用来做这个的。
你的代码里有客户端连接后 把SOcket赋给 clientSocket 也就是你只保存了最后一个连接的对象,
也就是说只有最后那个连接的客户端 才会接收到相应的信息




您好!最开始的代码我们今天有一些小的改动,改完后可以实现两个客户端同时连接该服务器,并可以分别给客户端传输图片,但一牵扯视频就不行了。。。


private void ServerStart()
{
//创建IPEndPoint实例
IPEndPoint localipep = new IPEndPoint(IPAddress.Any, 6000);
//创建一个套接字
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//将所创建的套接字与IPEndPoint绑定
serverSocket.Bind(localipep);
//设置套接字为收听模式
serverSocket.Listen(20);
threadWatch = new Thread(WatchConnection);
threadWatch.IsBackground = true;//设置为后台
threadWatch.Start();// 启动线程
}

void WatchConnection()
{

while (true)
{
try
{
allDone.Reset();
serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket);

allDone.WaitOne();
}


catch (Exception ex)
{
MessageBox.Show("listening Error: " + ex.Message);
}
}

}

//接收连接的回调函数
void Accept(IAsyncResult iar)
{
//调用EndAccept完成BeginAccept异步调用,返回一个新的Socket处理与客户的通信
Socket MyServer = (Socket)iar.AsyncState;
clientSocket = MyServer.EndAccept(iar);


clientThread = new Thread(new ThreadStart(ReceiveData));
clientThread.IsBackground = true;
clientThread.Start();

allDone.Reset();

//serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket);
//上面这句或下面这段是不是可以避免那种情况呢呢??
threadWatch = new Thread(new ThreadStart(WatchConnection));
threadWatch.IsBackground = true;//设置为后台
threadWatch.Start();// 启动线程
}




确实您说的是我今天早上一直纠结的问题,十分感谢!



1.你代码没法确定要回转给哪个客户端
2.你的代码如果是发送的数据包发送间隔在 不频繁情况下是可以收到。但如果包发多了发快了就产生了粘包的情况,就造成你收发的数据不正确,只要不正常。Socket就异常。线程不工作。所以。。。对你的要求来说上面的代码基本不可用。建义你看看我上面发的连接的代码,他解决粘包 还有发送对象问题 。这方面那个DEMO做的比较全面了。只能帮到你这了,因为要深入跟你讲这个,说个几天都说不完,关键的是 接收字节缓冲区 与 数据包协议 以及文件的分块(你的Image文件 一般一次是发不完的,所以要分成几次分)

读书人网 >C#

热点推荐