I want to make a chat. The server is made in console app and the client is made in winforms.
In client I write a nickname and connect to server. The server receives name from client. I add all clients that connect to server in a Dictionary list with the (string)name and (TcpClient)Socket. After, I want to send to every client the client list.
When I debug on server, the Sockets appear with DualMode,EnableBroadcast error. In client when I have to receive the list it stops and doesn't do anything.
Server
namespace MyServer
{
class MyServer
{
public Dictionary<string, TcpClient> clientList = new Dictionary<string, TcpClient>();
TcpListener server = null;
NetworkStream stream = null;
StreamReader streamReader = null;
StreamWriter streamWriter = null;
TcpClient clientSocket;
String messageReceived;
int number_clients = 0;
public MyServer(TcpClient clientSocket_connect)
{
stream = clientSocket_connect.GetStream();
streamReader = new StreamReader(stream);
streamWriter = new StreamWriter(stream);
receiveMessage(clientSocket_connect); // receive messages
}
public MyServer()
{
Thread thread = new Thread(new ThreadStart(run));
thread.Start();
}
public void receiveMessage(TcpClient client_Socket)
{
messageReceived = streamReader.ReadLine();
if (messageReceived.Substring(messageReceived.Length - 4) == "user")
{
String name = messageReceived.Substring(0, messageReceived.Length - 4);
bool found = false;
foreach (var namefound in clientList.Keys)
{
if (namefound == name)
{
found = true;
streamWriter.WriteLine("The user already exists");
streamWriter.Flush();
}
}
if (!found)
{
//show who's connected
Console.WriteLine(name + " is online");
number_clients++;
clientList.Add(name, client_Socket);
//send to client clientlist
String send = null;
foreach (var key in clientList.Keys)
{
send += key + ".";
}
foreach (var value in clientList.Values)
{
TcpClient trimitereclientSocket = value;
if (trimitereclientSocket != null)
{
NetworkStream networkStream = trimitereclientSocket.GetStream();
StreamWriter networkWriter = new StreamWriter(networkStream);
networkWriter.WriteLine(send + "connected");
networkWriter.Flush();
}
}
}
}
}
void run()
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
server = new TcpListener(ipAddress, 8000);
server.Start();
Console.WriteLine("Server started!");
while (true)
{
clientSocket = server.AcceptTcpClient();
new MyServer(clientSocket);
}
}
}
static void Main(string[] args)
{
MyServer server = new MyServer();
}
}
Client
namespace MyClient
{
class MyClient
{
List<string> clientList = new List<string>();
TcpClient client = null;
NetworkStream stream = nul
l;
StreamReader streamReader = null;
StreamWriter streamWriter = null;
bool connected;
String received_message;
public MyClient()
{
client = new TcpClient("127.0.0.1", 8000);
stream = client.GetStream();
streamReader = new StreamReader(stream);
streamWriter = new StreamWriter(stream);
}
public void sendClientName(String name)
{
streamWriter.WriteLine(Convert.ToString(name));
streamWriter.Flush();
}
public List<ClientName> receiveClientList()
{
List<ClientName> val = new List<ClientName>();
string name = Convert.ToString(streamReader.ReadLine());
if (name.Substring(0, name.Length - 9) == "connected")
{
ClientName client = new ClientName();
client.Nume = name;
val.Add(client);
}
return val;
}
}
}
Client Form
public partial class Form1 : Form
{
MyClient client = new MyClient();
public Form1()
{
InitializeComponent();
Thread receiveClients = new Thread(new ThreadStart(getMessages));
}
private void btnConnect_Click(object sender, EventArgs e)
{
client.sendClientName(txtNickname.Text + "user");
}
public void getMessages()
{
while (true)
{
lbClientsConnected.Items.Add(client.receiveClientList());
}
}
}
I was unable to reproduce any error when running your code. I don't know what you mean by "the Sockets appear with DualMode,EnableBroadcast error". That said, there are a number of fixable problems with the code, including some that pertain directly to your concern that "when I have to receive the list it stops and doesn't do anything."
Probably the biggest issue with the code is that you simply never start the client's receiving thread. You need to call the Start() method on the Thread object after it's been created:
public Form1()
{
InitializeComponent();
Thread receiveClients = new Thread(new ThreadStart(getMessages));
// The receiving thread needs to be started
receiveClients.Start();
}
Now, even with that fixed, you have a few other problems. The next big issue is that you are parsing the received text incorrectly. In your code, where you should be looking for the text "connected" at the end of the string, you instead extract the other part of the text (with the list of client names).
Your receiveClientList() method should instead look like this:
private const string _kconnected = "connected";
public List<string> receiveClientList()
{
List<string> val = new List<string>();
string name = Convert.ToString(streamReader.ReadLine());
// Need to check the *end* of the string for "connected" text,
// not the beginning.
if (name.EndsWith(_kconnected))
{
name = name.Substring(0, name.Length - _kconnected.Length);
val.Add(name);
}
return val;
}
(You didn't share the ClientName class in your question, and really the example doesn't need it; a simple string value suffices for the purpose of this exercise. ALso, I've introduced the const string named _kconnected, to ensure that the string literal is used correctly in each place it's needed, as well as to simplify usage.)
But even with those two issues fixed, you've still got a couple in the Form code where you actually handle the return value of the receive method. First, you are passing the List<T> object that is returned from the receive method to the ListBox.Items.Add() method, which would just result in the ListBox displaying the type name for the object, rather than its elements.
Second, because the code is executing in a thread other than the UI thread that owns the ListBox object, you must wrap the call in a call to Control.Invoke(). Otherwise, you'll get a cross-thread operation exception.
Fixing those two issues, you get this:
public void getMessages()
{
while (true)
{
// Need to receive the data, and the call Invoke() to add the
// data to the ListBox. Also, if adding a List<T>, need to call
// AddRange(), not Add().
string[] receivedClientList = client.receiveClientList().ToArray();
Invoke((MethodInvoker)(() => listBox1.Items.AddRange(receivedClientList)));
}
With those changes, the code will process the message sent by the client, and return the list of clients. That should get you further along. That said, you still have a number of other problems, including some fairly fundamental ones:
The biggest issue is that when you accept a connection in the server, you create a whole new server object to handle that connection. There are a number of reasons this isn't a good idea, but the main one is that the rest of the code seems to conceptually assume that a single server object is tracking all of the clients, but each connection will result in its own collection of client objects, each collection having just one member (i.e. that client).
Note that once you've fixed this issue, you will have multiple threads all accessing a single dictionary data structure. You will need to learn how to use the lock statement to ensure safe shared use of the dictionary across multiple threads.
Another significant problem is that instead of using the streamWriter you created when you first accepted the connection, you create a whole new StreamWriter object (referenced in a local variable named networkWriter) to write to the socket. In this very simple example, it works fine, but between buffering and the lack of thread safety, this incorrectly-designed code could have serious data corruption problems.
Less problematic, but worth fixing, is that your server code completely fails to take advantage of the fact that you're storing the clients in a dictionary, as well as that .NET has useful helper functions for doing things like joining a bunch of strings together. I would write your server's receiveMessage() method something more like this:
private const string _kuser = "user";
public void receiveMessage(TcpClient client_Socket)
{
messageReceived = streamReader.ReadLine();
if (messageReceived.EndsWith(_kuser))
{
String name = messageReceived.Substring(0, messageReceived.Length - _kuser.Length);
if (clientList.ContainsKey(name))
{
streamWriter.WriteLine("The user already exists");
streamWriter.Flush();
return;
}
//show who's connected
Console.WriteLine(name + " is online");
number_clients++;
clientList.Add(name, client_Socket);
string send = string.Join(".", clientList.Keys);
foreach (var value in clientList.Values.Where(v => v != null))
{
// NOTE: I didn't change the problem noted in #2 above, instead just
// left the code the way you had it, mostly. Of course, in a fully
// corrected version of the code, your dictionary would contain not
// just `TcpClient` objects, but some client-specific object specific
// to your server implementation, in which the `TcpClient` object
// is found, along with the `StreamReader` and `StreamWriter` objects
// you've already created for that connection (and any other per-client
// data that you need to track). Then you would write to that already-
// existing `StreamWriter` object instead of creating a new one each
// time here.
NetworkStream networkStream = value.GetStream();
StreamWriter networkWriter = new StreamWriter(networkStream);
networkWriter.WriteLine(send + "connected");
networkWriter.Flush();
}
}
}
The above is not exhaustive by any means. Frankly, you probably should spend more time looking at existing examples of network-aware code, e.g. on MSDN and Stack Overflow, as well as on tutorials on web sites, blogs, or in books. Even when you write the server in a one-thread-per-connection way as you seem to be trying to do here, there are lots of little details you really need to get correct, and which you haven't so far.
But I do hope the above is enough to get you past your current hurdle, and on to the next big problem(s). :)
Related
So i'm working on a C# Chat using TCP protocol and i cant figure out how to make the server send data received by a client to all the clients connected to him . So i tried to put all client into an arraylist and with the use of a "foreach" sending them data received by the server like in this topic but i failed .
For sending and receiving data i'm using Streams (StreamWriter / StreamReader).Each client is handled in a different thread by the server.
Question : How to send data to all the clients at the same time ?
Server :
static void LoopClients()
{
while (running)
{
TcpClient newClient = server.AcceptTcpClient();
arrClient.add(newClient)
Console.WriteLine("Connection accepted from " + ((IPEndPoint)newClient.Client.RemoteEndPoint).Address);
Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
t.Start(newClient);
}
}
static void HandleClient(object obj)
{
TcpClient client = (TcpClient)obj;
StreamWriter Writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader Reader = new StreamReader(client.GetStream(), Encoding.ASCII);
Boolean ClientConnected = true;
String Data = null;
var LEP = client.Client.RemoteEndPoint as IPEndPoint;
var LAD = LEP.Address;
while (ClientConnected)
{
Data = Reader.ReadLine();
Console.WriteLine(""+ LAD + " : " + Data);
Writer.WriteLine(LAD+" : "+Data+"");
Writer.Flush();
}
}
Thank You !
Essentially, you need to track all the clients somehow. This could be as simple as tracking all the StreamWriter in a synchronized collection, and ensure you remove from it when sessions terminate. For example:
StreamWriter Writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
try {
lock(allClients) { allClients.Add(Writer); }
while (ClientConnected)
{
...
}
} finally {
lock(allClients) { allClients.Remove(Writer); }
}
Now we need to do something when we want to send a message to everyone. Perhaps the simplest thing to to is a synchronized sweep:
lock(allClients) {
foreach(var writer in allClients)
try { writer.Send(message); } catch { /* log */ }
}
This synchronizes the entire collection - so as long as this is the only place that sends messages, then you know a: that you're never trying to send to the same socket twice at once, and b: that you're not going to break the iterator by having a socket add/remove.
Caveat: this is a very very crude and basic implementation of a multi-client server, and should really only be used as an introduction to the topic. "Real" multi-client servers should be much more paranoid that this.
PS: sorry my English I can understand but i'm not so good to write. corrections are very welcome
First of all, I read some answers here and already know my problem...
Well I'm here because I'll need to make some pained changes into my server if there is no other solution ...
Here we go.
I have a server and a client listening and answering in the same port.
Inside my server, I have only one thread that reads, processes and sends the result. No problem here, it's fine, but my client has multiple threads that is doing the same, and it's causing wrong messages like:
one thread send a message and wait the answer,
other thread send other message and the first thread capt it as an answer, so the real answer of the first is gives to the second, so all 2 receive wrong messages and cause a big confusion on client.
I'm almost sure that I'll need to use a port to read and one to write or a semaphore, but if I can get around it, it will be very helpful.
Any ideas?
My communication class:
public SenderAndRequester(string ipAdress, int port)
{
client = new TcpClient();
IPEndPoint ip_end = new IPEndPoint(IPAddress.Parse(ipAdress), port);
client.Connect(ip_end);
if (client.Connected)
{
stw = new StreamWriter(client.GetStream());
str = new StreamReader(client.GetStream());
stw.AutoFlush = true;
str.DiscardBufferedData();
}
}
public string communicate(string message)
{
var comming = str.ReadLineAsync();
stw.WriteLine(message);
return comming.Result;
}
and here the class that uses it
public MyConstructor(){
com = new Communicator(new SenderAndRequester(ip, port));
while (!com.InitServer(firstVar,secondVar,...)) ;
//code continue ...
mnt = new Task(Tracker, ctsMonitor.Token, TaskCreationOptions.LongRunning);
mnt.Start();
}
class main thread ...
private bool nextStatus()
{
//code continue..
if (!com.RequestNewStatus())
{
_Error = com.Error + " on communicator";
return false;
}
status = com.ServerStatus;
// code continue ...
return true;
}
and one of various other threads
private void Tracker()
{
while (!ctsMonitor.IsCancellationRequested)
{
//code continue
refresh = com.RequestCriticalData();
Thread.Sleep(100);
}
}
When i send a request to my server or a reply to my client, the message i send is always divided into multiple parts.
So i need to call Receive multiple times to get to the last part/frame.
Why does this happen.. is there a better way of sending and receiving an xml encoded string?
This is the code of my client:
private void SendRequestAsyncTaskStart<T>(object contextObj, T request)
{
ZmqContext context = (ZmqContext)contextObj;
ZmqSocket requestSocket = CreateServerSocket(context);
SerializeAndSendRequest(request, requestSocket);
}
private ZmqSocket CreateServerSocket(ZmqContext context)
{
var client = context.CreateSocket(SocketType.REQ);
client.Connect(_requestReplyEndpoint);
client.Linger = TimeSpan.Zero;
client.ReceiveReady += PollInReplyHandler;
return client;
}
public static string Serialize(this object obj)
{
string result;
using (var memoryStream = new MemoryStream())
{
using (var reader = new StreamReader(memoryStream))
{
var serializer = new DataContractSerializer(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
result = reader.ReadToEnd();
}
}
return result;
}
This is the code of my server:
private void ListenForRequestsThreadStart(object contextObj)
{
ZmqContext context = (ZmqContext)contextObj;
using (
ZmqSocket frontend = context.CreateSocket(SocketType.REP),
backend = context.CreateSocket(SocketType.DEALER))
{
string bindAddress = string.Format("tcp://*:{0}", _listenForRequetsPort);
frontend.Bind(bindAddress);
backend.Bind("inproc://backend");
frontend.ReceiveReady += HandleRequestReceived;
// polling
}
}
private void HandleRequestReceived(object sender, SocketEventArgs e)
{
string message;
bool hasNext;
do
{
message = socket.Receive(Encoding.ASCII);
hasNext = socket.ReceiveMore;
} while (hasNext);
// after calling Receive 3 times i get my actual message
}
Since you're sending via a socket you're at the mercy of the network. First, the network will have broken your message down in multiple packates each of which is received separately by your listener. Every now and then, the underlying socket on the listening machine will say to itself 'Got some incoming, but there's more to come. Wait a bit'. After a while it'll say, 'Oh well, give what I've got' and keep waiting'.
That's what's happening. In WCF, the WCF implementation gets its data via sockets which do exactly the same thing. But WCF waits till the whole message arrives before giving it to your waiting code. That's one of the advantages of using a Framework like WCF. It protects you from the metal.
Any message sent over TCP may be divided into several packets depending on its size. That's why you should never assume to get a message in one go, but read until you're sure you've received everything.
I am using Named Pipes to communicate with a process. I have been able to make it work with the following code. (Original code found here : via archive.org )
class ProgramPipeTest
{
public void ThreadSenderStartClient(object obj)
{
// Ensure that we only start the client after the server has created the pipe
ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".","ToSrvPipe",PipeDirection.Out,PipeOptions.None))
{
// The connect function will indefinately wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect();
Console.WriteLine("[Client] Pipe connection established");
using (StreamWriter sw = new StreamWriter(pipeStream))
{
sw.AutoFlush = true;
string temp;
Console.WriteLine("Please type a message and press [Enter], or type 'quit' to exit the program");
while ((temp = Console.ReadLine()) != null)
{
if (temp == "quit") break;
sw.WriteLine(temp);
}
}
}
}
public void ThreadStartReceiverClient(object obj)
{
// Ensure that we only start the client after the server has created the pipe
ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "FromSrvPipe", PipeDirection.In, PipeOptions.None))
{
// The connect function will indefinately wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect();
Console.WriteLine("[ClientReceiver] Pipe connection established");
using (StreamReader sr = new StreamReader(pipeStream))
{
// Display the read text to the console
string temp;
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("Received from server: {0}", temp);
}
}
}
}
static void Main(string[] args)
{
// To simplify debugging we are going to create just one process, and have two tasks
// talk to each other. (Which is a bit like me sending an e-mail to my co-workers)
ProgramPipeTest Client = new ProgramPipeTest();
Thread ClientThread = new Thread(Client.ThreadSenderStartClient);
Thread ReceivedThread = new Thread(Client.ThreadStartReceiverClient);
ClientThread.Start();
ReceivedThread.Start();
}
}
Everything works as intended. I am able to issue commands to my target process (audacity).
My issue is, I basically want to wrap a C# GUI around this code, but am not sure how to modify it so that the communication is done without having to use the console, as commands would be issued via the GUI or from the code.
I have tried turning the streamWriter sw into a class variable, exposing it via property and calling sw.WriteLine() with a method, but that doesn't seem to work.
So I am unsure how to encapsulate the stream back and forth nicely within an object.
I found this article which seemed like it was spot on, Using Named Pipes to Connect a GUI to a Console App in Windows, but unfortunately it does not seem to come with any code and is kind of over my head without any to refer to.
So how can I use named pipes without having to use the console to issue the commands ?
What you want to do is take the main pieces of logic which are the sender, the receiver out of that code and rewrite it into a re-usable class that can be used like a purpose-specific wrapper class.
Perhaps the code below could serve as a guideline (I have NOT checked to see if this works, it might require minor changes)
public sealed class ResponseReceivedEventArgs : EventArgs
{
public ResponseReceivedEventArgs(string id, string response)
{
Id = id;
Response = response;
}
public string Id
{
private set;
get;
}
public string Response
{
private set;
get;
}
}
public delegate void ResponseReceived(object sender, ResponseReceivedEventArgs e);
public sealed class NamedPipeCommands
{
private readonly Queue<Tuple<string, string>> _queuedCommands = new Queue<Tuple<string,string>>();
private string _currentId;
private readonly Thread _sender;
private readonly Thread _receiver;
// Equivalent to receiving a "quit" on the console
private bool _cancelRequested;
// To wait till a response is received for a request and THEN proceed
private readonly AutoResetEvent _waitForResponse = new AutoResetEvent(false);
// Lock to modify the command queue safely
private readonly object _commandQueueLock = new object();
// Raise an event when a response is received
private void RaiseResponseReceived(string id, string message)
{
if (ResponseReceived != null)
ResponseReceived(this, new ResponseReceivedEventArgs(id, message));
}
// Add a command to queue of outgoing commands
// Returns the id of the enqueued command
// So the user can relate it with the corresponding response
public string EnqueueCommand(string command)
{
var resultId = Guid.NewGuid().ToString();
lock (_commandQueueLock)
{
_queuedCommands.Enqueue(Tuple.Create(resultId, command));
}
return resultId;
}
// Constructor. Please pass in whatever parameters the two pipes need
// The list below may be incomplete
public NamedPipeCommands(string servername, string pipeName)
{
_sender = new Thread(syncClientServer =>
{
// Body of thread
var waitForResponse = (AutoResetEvent)syncClientServer;
using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.Out, PipeOptions.None))
{
pipeStream.Connect();
using (var sw = new StreamWriter(pipeStream) { AutoFlush = true })
// Do this till Cancel() is called
while (!_cancelRequested)
{
// No commands? Keep waiting
// This is a tight loop, perhaps a Thread.Yield or something?
if (_queuedCommands.Count == 0)
continue;
Tuple<string, string> _currentCommand = null;
// We're going to modify the command queue, lock it
lock (_commandQueueLock)
// Check to see if someone else stole our command
// before we got here
if (_queuedCommands.Count > 0)
_currentCommand = _queuedCommands.Dequeue();
// Was a command dequeued above?
if (_currentCommand != null)
{
_currentId = _currentCommand.Item1;
sw.WriteLine(_currentCommand.Item2);
// Wait for the response to this command
waitForResponse.WaitOne();
}
}
}
});
_receiver = new Thread(syncClientServer =>
{
var waitForResponse = (AutoResetEvent)syncClientServer;
using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.In, PipeOptions.None))
{
pipeStream.Connect();
using (var sr = new StreamReader(pipeStream))
// Do this till Cancel() is called
// Again, this is a tight loop, perhaps a Thread.Yield or something?
while (!_cancelRequested)
// If there's anything in the stream
if (!sr.EndOfStream)
{
// Read it
var response = sr.ReadLine();
// Raise the event for processing
// Note that this event is being raised from the
// receiver thread and you can't access UI here
// You will need to Control.BeginInvoke or some such
RaiseResponseReceived(_currentId, response);
// Proceed with sending subsequent commands
waitForResponse.Set();
}
}
});
}
public void Start()
{
_sender.Start(_waitForResponse);
_receiver.Start(_waitForResponse);
}
public void Cancel()
{
_cancelRequested = true;
}
public event ResponseReceived ResponseReceived;
}
You can see that I have created abstractions for the Console.ReadLine (the command queue) and Console.WriteLine (the event). The "quit" is also a boolean variable that is set by the "Cancel()" method now. Obviously this isn't the most optimal/correct way of doing it - I am just showing you one way to relate the imperative code from above into a wrapper class that can be re-used.
I have a simple class that handles the connection being made between a client and server.
To let more than one user communicate with the server at one time each new Client connection is made on a separate thread.
In this class I create two streams that act as the inbound and outbound streams for the client. I create the fields first and then initialise the object in a separate method, simply because the object is used in several other places.
I've come to the point where I want to refactor the code to make it more robust, my first port of call was memory management. I've come to love the using() statement but noticed that I can't really see a way to do implement it due to the way the code is structured.
This means I have a fairly annoying method that is just used for closing the underlying connections and nothing more.
Furthermore, I came to implement exception handling and was curious whether the notion of wrapping the entire code in a method with a try{} statement and then having sequential catch() blocks with the applicable exception types was the best idea.
I hope I explained myself correctly, I'll post a snippet for you to look at.
Thanks!
//Fields
TcpClient tcpClient;
//The thread that will send information to the client
private Thread thrSender;
private StreamReader srReceiver;
private StreamWriter swSender;
private string currentUser;
private string strResponse;
//The constructor of the class takes in a TCP connection
public Connection(TcpClient tcpCon)
{
tcpClient = tcpCon;
//The thread that accepts the client and waits messages
thrSender = new Thread(AcceptClient);
//The thread calls the AcceptClient method
thrSender.Start();
}
private void CloseConnection()
{
//Close the currently open objects
tcpClient.Close();
srReceiver.Close();
swSender.Close();
}
//Occurs when a new client is accepted
private void AcceptClient()
{
srReceiver = new StreamReader(tcpClient.GetStream());
swSender = new StreamWriter(tcpClient.GetStream());
//Read account information from the client
currentUser = srReceiver.ReadLine();
//Examine response from client
if (currentUser != "")
{
//Store the user name in the hash table
if (ChatServer.htUsers.Contains(currentUser) == true)
{
//0 means not connected - Writes error to Client and Server log
swSender.WriteLine("0|This username already exists.");
swSender.Flush();
CloseConnection();
return;
}
//More if/else if/else statements
//...
}
}
You can dispose of the two streams fairly easily within the AcceptClient method by making them local variables since they aren't referenced elsewhere something like this:
private void AcceptClient()
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
The tcpClient is more tricky because it is being created on one thread and cleaned up on another. Unless you can change that then perhaps the best option is going to be to implement the cleanup within a try/finally.
private void AcceptClient()
{
try
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
finally
{
tcpClient.Dispose();
}
}
The finally clause will get called whether or not the try clause throws an exception.