首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

C#大牛!在 socket通信中,多客户端与一个服务器端异步通信时,服务器监听客户端套接字后,怎么分别开启一个线程去进行数据传送?

2013-07-20 
求助C#大牛!!在 socket通信中,多客户端与一个服务器端异步通信时,服务器监听客户端套接字后,如何分别开启

求助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文件 一般一次是发不完的,所以要分成几次分)

热点排行