冲突的TCP套接字侦听器和多线程套接字工作程序

时间:2015-03-13 15:30:26

标签: c# multithreading wcf sockets tcp

我目前正在使用一个由三个部分组成的应用程序,它应该可以工作多线程,但由于某些原因,每当我使用多个线程时,我都无法使其正常工作。

我已经无数次地使用了我的代码,虽然我确认并做了一些改进但仍然无法找到我的错误。

所以我有一个客户端应用程序,它是一种测试服务性能的基准测试应用程序,它定义了特定操作将运行的线程数(基本上,要实例化多少个TCP客户端)。

以下是该客户的代码:

private void stressTestButton_Click(object sender, EventArgs e)
{
    server = txtServer.Text;
    port = Convert.ToInt32(txtPort.Text);

    if (this.numberOfThreads.Value != 0 && this.executionTime.Value != 0)
    {
        newThreads = new Thread[(int)this.numberOfThreads.Value];

        this.threadTimer = new Stopwatch();
        this.threadTimer.Reset();

        //Clear stressResultsBox
        this.stressResultBox.Items.Clear();
        this.totalOp = 0;
        this.opFinishedCheck = 0;
        this.xmlTrimed = XElement.Parse(this.inputTextBox.Text).ToString(SaveOptions.DisableFormatting);

        for (int i = 0; i < this.numberOfThreads.Value; i++)
        {
            try
            {
                if (i == 0) //run once
                    threadTimer.Start();
                //Create Threads
                newThreads[i] = new Thread(ThreadSlot);
                newThreads[i].Start(); //Start Thread
                if (this.threadTimer.Elapsed.Seconds >= this.executionTime.Value)
                {
                    break;
                }
            }
            catch (Exception ex)
            {
                stressResultBox.Items.Add(ex.Message);
                break;
            }
        }
    }
}

/// <summary>
/// Client thread slot creation
/// </summary>
public void ThreadSlot()
{
    // Set different data in each thread's data slot.
    Thread.SetData(Thread.GetNamedDataSlot("Random"), randomGenerator.Next(1, 200));

    int index = 0;
    int threadProgress = 0;
    this.Invoke(new MethodInvoker(delegate()
    {
        index = this.stressResultBox.Items.Add("Sent request, waiting for response");
    }));

    //Run thread until timeout
    while (true)
    {
        try
        {
            if (this.threadTimer.Elapsed.Seconds < this.executionTime.Value)
            {
                string response = SendRequest(server, port, this.xmlTrimed);
                this.Invoke(new MethodInvoker(delegate()
                {
                    this.stressResultBox.Items[index] = "Thread: " + (index + 1) + " Operations: " + (threadProgress + 1) + " Time: " + threadTimer.Elapsed.Seconds.ToString() + "s " + threadTimer.Elapsed.Milliseconds.ToString() + "ms";
                    threadProgress++;
                }));
            }
            else
            {
                break;
            }
        }
        catch (Exception ex)
        {
            this.Invoke(new MethodInvoker(delegate()
            { this.stressResultBox.Items[index] = ex.Message; }));
            break;
        }
    }
    this.Invoke(new MethodInvoker(delegate() { this.totalOp += threadProgress; this.opFinishedCheck += 1; }));
    if (this.opFinishedCheck == ((int)this.numberOfThreads.Value - 1))
    {
        this.Invoke(new MethodInvoker(delegate()
        {
            this.threadTimer.Stop();
            this.stressResultBox.Items.Add("#Total Operations: " + this.totalOp);
        }));
    }
}

/// <summary>
/// SendRequest handler
/// </summary>
/// <param name="server">server IP to send the request</param>
/// <param name="port">server port to send the request</param>
/// <param name="data">request</param>
/// <returns>server answer</returns>
private static string SendRequest(string server, int port, string data)
{
    IPAddress ipAddress = null;
    IPHostEntry ipHostInfo = Dns.GetHostEntry(server);
    for (int i = 0; i < ipHostInfo.AddressList.Length; ++i)
    {
        if (ipHostInfo.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
        {
            ipAddress = ipHostInfo.AddressList[i];
            break;
        }
    }
    if (ipAddress == null)
        throw new Exception("No IPv4 address for server");

    TcpClient client = new TcpClient();

    client.Connect(ipAddress, port); // Connect
    NetworkStream networkStream = client.GetStream();
    StreamWriter writer = new StreamWriter(networkStream);
    StreamReader reader = new StreamReader(networkStream);
    writer.AutoFlush = true;
    writer.WriteLine(data);
    string response = reader.ReadLine();

    //reader.Close();
    //client.GetStream().Close();
    client.Close();

    return response;
}

此客户端调用TCP服务器,该服务器有两个类:侦听器和Worker。工作人员负责执行操作并调用WCF服务。此侦听器继续侦听来自客户端的连接,并在每个客户端实例的不同线程上实例化Worker。 虽然调试一切似乎都在使用Thread和Client实例化正确运行。

所以这是我的听众:

internal class SocketListenerService
{
    private static void Main(string[] args)
    {
        try
        {
            int port = 50000;
            AsyncService service = new AsyncService(port);
            service.Run(); // very specific service
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.ReadLine();
        }
    }
} // Program

public class AsyncService
{
    private IPAddress ipAddress;
    private int port;

    public AsyncService(int port)
    {
        // set up port and determine IP Address
        this.port = port;
        string hostName = Dns.GetHostName();
        IPHostEntry ipHostInfo = Dns.GetHostEntry(hostName);

        this.ipAddress = IPAddress.Any; // allows requests to any of server's  addresses

        this.ipAddress = null;
        for (int i = 0; i < ipHostInfo.AddressList.Length; ++i)
        {
            if (ipHostInfo.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
            {
                this.ipAddress = ipHostInfo.AddressList[i];
                break;
            }
        }
        if (this.ipAddress == null)
            throw new Exception("No IPv4 address for server");
    } // AsyncService ctor

    /// <summary>
    /// SocketListener run method
    /// Initializes a socketworker for every client connection
    /// </summary>
    public void Run()
    {
        TcpListener listener = new TcpListener(this.ipAddress, this.port);
        listener.Start();
        Console.WriteLine("Service is now running on " + this.ipAddress.ToString() + ":" + this.port);
        Console.WriteLine("Hit <enter> to stop service\n");

        while (true)
        {
            try
            {
                TcpClient tcpClient = listener.AcceptTcpClient();

                //Threaded...
                SocketWorker sw = new SocketWorker(tcpClient);
                Thread workerThread = new Thread(sw.Run);
                workerThread.Start();

                //Not threaded...
                //sw.Run();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    } // Start

    private void threadSlot(TcpClient tcpClient)
    {
        SocketWorker sw = new SocketWorker(tcpClient);
        //sw.Run();
    }
} // AsyncServer

然后,我有一个我称之为工人的课程。工人将负责执行预期的实际工作/操作。 这是我的工人:

internal class SocketWorker
{
    /// <summary>
    /// SocketWorker run method
    /// Starts processing the client request
    /// </summary>
    /// <param name="tcpClient">tcpclient connection</param>
    /// 
    private TcpClient tcpClient = null;
    private int instanceCounter = 0;

    public SocketWorker(TcpClient tcpCli)
    {
        tcpClient = tcpCli;
    }

    /// <summary>
    /// SocketWorker run method
    /// Starts processing the client request
    /// </summary>
    /// <param name="tcpClient">tcpclient connection</param>
    public async void Run()
    {
        instanceCounter++;
        Console.WriteLine(instanceCounter.ToString());

        try
        {
            while (tcpClient.Connected)
            {
                NetworkStream networkStream = tcpClient.GetStream();
                StreamReader reader = new StreamReader(networkStream);

                string request = reader.ReadLine();
                if (request != null)
                {
                    StreamWriter writer = new StreamWriter(networkStream);
                    writer.AutoFlush = true;
                    string response = await Execute(request, tcpClient);//Executes the request
                    //Console.WriteLine("Response: " + response);
                    await writer.WriteLineAsync(response);
                    //writer.Close();
                    //tcpClient.GetStream().Close();
                    //tcpClient.Close();
                }
                else
                    break; // client closed connection
            }
            tcpClient.GetStream().Close();
            tcpClient.Close();

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            if (tcpClient.Connected)
            {
                tcpClient.GetStream().Close();
                tcpClient.Close();
            }
        }
    } //Run

    /// <summary>
    /// Executes client request
    /// </summary>
    /// <param name="xml">received client xml</param>
    /// <returns>xml response to be sent to the client</returns>
    private async Task<string> Execute(string xml, TcpClient tcpClient)
    {
        try
        {
            ServiceReferenceIISSrv.serviceClient clientService = new ServiceReferenceIISSrv.serviceClient();
            //Call the search service
            Task<byte[]> searchResult = clientService.SearchAsync(strct);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
            throw;
        }
        finally
        {
            clientService.Close();
        }

        //Console.WriteLine(ll);
        //tcpClient.Close();
        return ll;
    } // Execute
}

最后,我的WCF服务使用net.TCP协议在IIS上托管进行通信,并使用以下ServiceBehaviour进行定义:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]

由于这是很多信息,这里是简化的场景:

ClientTool =&gt; TCP套接字 - &gt; Listener = new Worker =&gt; net.TCP - &gt; WCF

我知道这是很多代码,你们大多数人都不会真正阅读它(我知道我可能不会这么做),但我决定把它全部放在这里,因为我没有看到任何代码在初始化线程时都没有实例化任何类的错误。

但正在发生的事情是,即使他们同时开始,我也只能回复其中一个主题。如果,我正在一个客户端工具的一个实例上运行基准测试只有一个线程,然后我在客户端工具的另一个实例(例如,在另一台计算机上)上启动基准测试,第一个实例停止获得回复,第二个实例停止获得回复效果很好。

那么,任何人都能看到我做错的事吗?另外,在这种情况下,将任务混合为线程是否会出现任何类型的并发问题?

提前谢谢。

0 个答案:

没有答案