can somebody tell me why my code is not working?
class Connection
{
public static StreamWriter writer;
public static string SERVER;
private static int PORT;
private static string USER;
private static string NICK;
private static string CHANNELS;
private Thread connection;
private Thread ping;
public Connection()
{
connection = new Thread(new ThreadStart(this.Run));
ping = new Thread(new ThreadStart(this.Ping));
}
public void Start(string server, int port, string ident, string realname, string nick, string channels)
{
SERVER = server;
PORT = port;
USER = "USER " + ident + " 8 * :" + realname;
NICK = nick;
CHANNELS = channels;
connection.Start();
}
public void Ping()
{
while (true)
{
try
{
Connection.writer.WriteLine("PING :" + SERVER);
Connection.writer.Flush();
Thread.Sleep(15000);
}
catch (Exception e) { Console.WriteLine(e.ToString()); }
}
}
public void Run()
{
NetworkStream stream;
TcpClient irc;
string inputLine;
StreamReader reader;
try
{
irc = new TcpClient(SERVER, PORT);
stream = irc.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
writer.WriteLine(USER);
writer.Flush();
writer.WriteLine("NICK " + NICK);
writer.Flush();
Thread.Sleep(5000);
writer.WriteLine("JOIN " + CHANNELS);
writer.Flush();
while (true)
{
while ((inputLine = reader.ReadLine()) != null)
{
Console.WriteLine(inputLine);
}
writer.Close();
reader.Close();
irc.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
Run();
}
}
}
It connects to the server fine, but the ping Thread and voids seem to not functioning at all! and i dont know why, everything seems correct unless im missing something very obviousC
You haven't started your ping thread. Call Start method of it.
Another note - don't use Thread.Sleep for threads/process synchronization. From my experience, code using it is usually slow, unreliable and hard to maintain. Use Monitor class or various WaitHandle implementations (e.g. AutoResetEvent) or whatever. For client/server communication try to wait until server response to your request (if such is defined in protocol), not just timeout.
Also, if you are starting new threads either make this threads stop (e.g. in Dispose method of your class) or set IsBackground property, or, preferrably, both. Otherwise these threads will block your process from stopping.
Related
I'm hoping someone can tell me why I'm getting an object disposed exception in my tcpListener/tcpClient code.
In the acceptConnections and connectToServer methods I use the keepalive method to tell me when I get disconnected and it works fine.
However, if I uncomment the for loop for my sendMsg method I will get an ObjectDisposedException on the server and an IOException on the client.
The tcpClient.getStream()'s NetworkStream in SendMsg seems to be the issue but I am unsure why it would get a disposed stream. Do I need 2 threads to work with it?
static void Main(string[] args)
{
server.Listen();
server.AcceptConnections();
client.ConnectToServer();
//for (int i = 0; i < 5; i++) {
// Thread.Sleep(3000);
// server.SendMsg("SENT MSG");
//}
Console.ReadLine();
}
public async void SendMsg(String message) {
try {
NetworkStream networkStream = tcpClient.GetStream();
using (var writer = new StreamWriter(networkStream)) {
await writer.WriteLineAsync(message);
Console.WriteLine("msg sent");
};
} catch (Exception e) {
}
}
private async void KeepAlive(TcpClient tcpClient) {
bool clientConnected = true;
using (NetworkStream networkStream = tcpClient.GetStream())
using (var reader = new StreamReader(networkStream))
using (var writer = new StreamWriter(networkStream)) {
writer.AutoFlush = true;
char keepalive = '0';
while (clientConnected) {
try {
await writer.WriteLineAsync(keepalive);
string dataFromClient = await reader.ReadLineAsync();
Console.WriteLine("Server: " + dataFromClient);
Thread.Sleep(500);
} catch (IOException e){
} catch(ObjectDisposedException e) {
clientConnected = false;
clientsConnected--;
} catch (Exception e){
}
}
}
}
EDIT: posting my AcceptConnections method as well
public async void AcceptConnections() {
while (true) {
while (clientsConnected <= maxConnections) {
try {
tcpClient = await tcpListener.AcceptTcpClientAsync();
KeepAlive(tcpClient);
} catch (Exception e) {
Console.WriteLine("TOP EXCEPTION :: " + e);
}
clientsConnected++;
Console.WriteLine("SERVER Clients connected: " + clientsConnected);
}
}
}
Your SendMsg method uses using on a StreamWriter. The default for a StreamWriter is to cascade the dispose, so this will close the NetworkStream. If that isn't your intent, you need to pass leaveOpen: true to the constructor overload.
Frankly though, there's no reason to use StreamWriter here - I would suggest dealing with the Stream and Encoding APIs directly. One advantage of StreamWriter is that internally it might re-use a buffer for the byte[] work, but that "advantage" is moot if you're only using it for one Write before disposing it, and can be readily achieved with a buffer pool.
My client part is closing after I do a request to server a second time, but without errors, it just goes away:
class Client
{
static void Main(string[] args)
{
try
{
Console.Title = "Client";
AsyncClient client = new AsyncClient(60101);
client.Connect();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.Read();
}
}
}
public class AsyncClient
{
private IPAddress ipAddress;
private int port;
/// <summary>
/// Connects to the local IPAddress.
/// </summary>
/// <param name="port"></param>
public AsyncClient(int port)
{
this.port = port;
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
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 has been found");
}
public AsyncClient(string ip, int port)
{
this.port = port;
IPAddress.TryParse(ip, out ipAddress);
}
public async void Connect()
{
int attempts = 0;
TcpClient client = new TcpClient();
while (!client.Connected)
{
try
{
attempts++;
client.Connect(this.ipAddress, this.port);
Console.Clear();
Console.WriteLine("Connected");
await Process(client);
}
catch (SocketException)
{
Console.Clear();
Console.WriteLine("Connection Attempts: {0}", attempts);
}
}
}
public async Task Process(TcpClient tcpClient)
{
try
{
NetworkStream stream = tcpClient.GetStream();
StreamWriter writer = new StreamWriter(stream);
StreamReader reader = new StreamReader(stream);
writer.AutoFlush = true;
while (true)
{
Console.WriteLine("Enter a Request: ");
await writer.WriteLineAsync(Console.ReadLine());
string response = await reader.ReadLineAsync();
if (response != null)
Console.WriteLine(response);
else
break;
}
}
catch (Exception)
{
//
}
finally
{
if (!tcpClient.Connected)
{
for (int i = 5; i >= 1; i--)
{
Console.WriteLine($"Connection lost, trying to reconnect in {i}");
Thread.Sleep(1000);
}
Connect();
}
}
}
}
This under is the server side code, it's just for study purpose. I am trying to learn how to work with sockets and after trying with many different ways like "begin" methods, etc, I feel like I've finally found the right way to do it, since with the others I had problems like concurrent access, closing connection, etc, but this time I believe I got it right.
Am I wrong or this time it's really all good with my code?
class Server
{
static void Main(string[] args)
{
try
{
Console.Title = "Server";
AsyncServer server = new AsyncServer(60101);
server.Run();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.Read();
}
}
}
public class AsyncServer
{
private IPAddress ipAddress;
private int port;
public AsyncServer(int port)
{
this.port = port;
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
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");
}
public async void Run()
{
TcpListener listener = new TcpListener(this.ipAddress, this.port);
listener.Start();
Console.WriteLine($"Server is now online on Port: {this.port}");
Console.WriteLine("Hit <Enter> to stop the service");
while (true)
{
try
{
TcpClient tcpClient = await listener.AcceptTcpClientAsync();
Process(tcpClient);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private async void Process(TcpClient tcpClient)
{
string clientEndPoint = tcpClient.Client.RemoteEndPoint.ToString();
Console.WriteLine($"Received connection request from {clientEndPoint}");
try
{
NetworkStream networkStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(networkStream);
StreamWriter writer = new StreamWriter(networkStream);
writer.AutoFlush = true;
while (true)
{
string request = await reader.ReadLineAsync();
if (request != null)
Handle(request, writer);
else
break;
}
}
catch (Exception)
{
//
}
finally
{
if (tcpClient.Connected)
tcpClient.Close();
Console.WriteLine($"{clientEndPoint} has closed the connection, aborting operation");
}
}
private string Response(string request)
{
Thread.Sleep(10000);
if (request.ToLower() == "get time")
return DateTime.Now.ToLongTimeString();
else
return $"\"{request}\" is a invalid request";
}
private async void Handle(string request, StreamWriter writer)
{
try
{
Console.WriteLine($"Received request: {request}");
string response = Response(request);
Console.WriteLine($"Computed response is: {response}");
await writer.WriteLineAsync(response);
}
catch (Exception)
{
//
}
}
}
Plus, I would like to know, if I want to make it work on my external IP, so ppl from different IPs can use it, what should I change?
My client part is closing after I do a request to server a second
time, but without errors, it just goes away:
The reason for this is that your client calls async method client.Connect(), but doesn't (a)wait this method, so execution on the main thread continues to the next line, Console.Read(), which blocks only until you press [ENTER] for the second time (first [ENTER] is consumed by Console.ReadLine() in a Process() method). Then there is nothing for main thread to do and main thread (as well as whole client application) exits.
As a side note, it is good practise to name all async methods such that it's name ends with 'Async', so that caller of such a method is aware of it's async behaviour and doesn't forget to (a)wait the method. So you should rename Connect to ConnectAsync and Process to ProcessAsync.
Solution is to change return type of Connect method to Task, making method awaitable (it is strongly discouraged for async method to return void anyway):
public async Task ConnectAsync()
and add .Wait() in the Main method, which blocks main thread, until ConnectAsync() exits.
client.ConnectAsync().Wait();
In C# 7.1 you could also use async Main instead:
static async Task Main(string[] args)
{
...
await client.ConnectAsync();
...
}
Plus, I would like to know, if I want to make it work on my external
IP, so ppl from different IPs can use it, what should I change?
Just make sure that if server has more than one IP address, TcpListener listens on the correct one, and enable port or application in the firewall.
I used this code once before, and it worked. Now, every time it tries to connect to an IRC server, I get the error: 'Cannot read from a closed text reader'
I've changed the adresses for privacy
This is my code:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace IRCBot
{
class Program
{
}
class IrcBot
{
// Irc server to connect
public static string SERVER = "irc.rizon.net";
// Irc server's port (6667 is default port)
private static int PORT = 6660;
// User information defined in RFC 2812 (Internet Relay Chat: Client Protocol) is sent to irc server
private static string USER = "irc_bot";
// Bot's nickname
private static string NICK = "BotNick";
// Channel to join
private static string CHANNEL = "#testing";
// StreamWriter is declared here so that PingSender can access it
public static StreamWriter writer;
static void Main(string[] args)
{
NetworkStream stream;
TcpClient irc;
string inputLine;
StreamReader reader;
string nickname;
try
{
irc = new TcpClient(SERVER, PORT);
stream = irc.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
// Start PingSender thread
PingSender ping = new PingSender();
ping.Start();
writer.WriteLine(USER);
writer.Flush();
writer.WriteLine("NICK " + NICK);
writer.Flush();
writer.WriteLine("JOIN " + CHANNEL);
writer.Flush();
while (true)
{
while ((inputLine = reader.ReadLine()) != null)
{
if (inputLine.EndsWith("JOIN :" + CHANNEL))
{
// Parse nickname of person who joined the channel
nickname = inputLine.Substring(1, inputLine.IndexOf("!") - 1);
// Welcome the nickname to channel by sending a notice
writer.WriteLine("NOTICE " + nickname + " :Hi " + nickname +
" and welcome to " + CHANNEL + " channel!");
writer.Flush();
// Sleep to prevent excess flood
Thread.Sleep(2000);
}
}
// Close all streams
writer.Close();
reader.Close();
irc.Close();
}
}
catch (Exception e)
{
// Show the exception, sleep for a while and try to establish a new connection to irc server
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
string[] argv = { };
Main(argv);
}
}
}
class PingSender
{
static string PING = "PING :";
private Thread pingSender;
// Empty constructor makes instance of Thread
public PingSender()
{
pingSender = new Thread(new ThreadStart(this.Run));
}
// Starts the thread
public void Start()
{
pingSender.Start();
}
// Send PING to irc server every 15 seconds
public void Run()
{
while (true)
{
IrcBot.writer.WriteLine(PING + IrcBot.SERVER);
IrcBot.writer.Flush();
Thread.Sleep(15000);
}
}
}
}
Close all streams must be outside while:
while (true)
{
while ((inputLine = reader.ReadLine()) != null)
{
....
}
}
// Close all streams
writer.Close();
reader.Close();
irc.Close();
Move all your stream closing lines to "finally" block:
try
{
...
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
string[] argv = { };
Main(argv);
}
finally
{
//Close all streams
writer?.Close();
reader?.Close();
irc?.Close();
}
Note, I've used new C#6 null-propagation operator ?. here cause your streams can be null. If you're using C# ver<6 then write it like this:
if (writer!=null) writer.Close();
I am in desperate need of help. I have essentially created a program that (will use) encryption to send messages back and forth. The encryption part is working fine, however I am fairly new to Threads and I can not for the life of me get my Client/Server pieces of the application to line up. The chat program is direct IP connection using TCP, so each host is a client and a server. The issue I appear to be having, when I debug, is that the server thread is either not ready when the Client tries to connect to it, or if it is ready it will not relinquish the Thread so the Client can connect! I have been working on this for hours and it is very frustrating.. I hope someone can help! I've included my code below.
This is my code snippet from my MainForm, which constructs the Client and Server aspects:
private void InitializeComponent() {
server = new ServerSide("127.0.0.1",7865);
servThread = new Thread(new ThreadStart(server.begin));
client = new ClientSide("127.0.0.1",7865);
clientThread = new Thread(new ThreadStart(client.begin));
servThread.Start();
clientThread.Start();
//servThread.Join();
//clientThread.Join();
}
This is my ServerSide code:
public class ServerSide
{
String IpString;
int tcpPort;
bool goodToGo = false;
System.Net.IPAddress ipAddress = null;
public ServerSide(String ip, int tcpPort)
{
IpString = ip;
bool isValidIp = System.Net.IPAddress.TryParse(IpString, out ipAddress);
if (isValidIp == true) // check if the IP is valid, set the bool to true if so
{
goodToGo = true;
}
else
{
goodToGo = false;
}
}
public void begin()
{
try
{
IPAddress ipAd = IPAddress.Parse(IpString);
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, tcpPort);
Socket s = null;
/* Start Listening at the specified port */
while (true)
{
myList.Start();
if (myList.Pending())
{
s = myList.AcceptSocket();
break;
}
}
String toReceive = "";
while (true)
{
byte[] b = new byte[4096];
int k = s.Receive(b);
for (int i = 0; i < k; i++)
toReceive += Convert.ToString((Convert.ToChar(b[i])));
// ASCIIEncoding asen = new ASCIIEncoding();
var form = MainForm.ActiveForm as MainForm;
if (form != null)
{
form.messageReceived(toReceive);
}
toReceive = "";
}
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
}
ClientSide code:
public class ClientSide
{
private String IpString;
private int tcpPort;
private TcpClient tcpInt;
private static Stream stm;
private System.Net.IPAddress ipAddress = null;
private bool goodToGo = false;
public ClientSide(String ip, int tcpPort)
{
IpString = ip;
this.tcpPort = tcpPort;
bool isValidIp = System.Net.IPAddress.TryParse(IpString, out ipAddress);
if (isValidIp == true)
{
goodToGo = true;
}
else
{
goodToGo = false;
}
}
public void begin()
{
try
{
tcpInt = new TcpClient();
// Console.WriteLine("Connecting.....");
tcpInt.Connect(IpString, tcpPort);
// use the ipaddress as in the server program
// Console.WriteLine("Connected");
// String str = Console.ReadLine();
stm = tcpInt.GetStream();
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
public void sendMessage(String str)
{
// stm = tcpInt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
stm.Write(ba, 0, ba.Length);
/** byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
Console.Write(Convert.ToChar(bb[i]));*/
}
}
}
Once again.. what typically happens is my Client receives an error that the host actively refused the connection.. but I do not know how to time them. I am looking for how to have my server listening for TCP Connections, but still manage to go to my other thread to create the TCP Connecion to send the server (I am testing this on localhost currently).
Thanks.
In the constructor of the ServerSide class, you forgot to initialize the tcpPort member. Because you forgot, the server will try to listen to port 0 and the client will try to connect to port 7865, and it will fail.
Try adding this code to the constructor in the ServerSide class.
this.tcpPort = tcpPort;
As for the threads, you might have a problem if the client thread tries to connect before the server thread has started listening. You can use a loop to try to connect a number of times (let's say 10), with a timeout (let's say 1 second) if you don't succeed. This way, you will retry 10 times and give up after that.
I have an update server that sends client updates through TCP port 12000. The sending of a single file is successful only the first time, but after that I get an error message on the server "Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host". If I restart the update service on the server, it works again only one time. I have normal multithreaded windows service.
SERVER CODE
namespace WSTSAU
{
public partial class ApplicationUpdater : ServiceBase
{
private Logger logger = LogManager.GetCurrentClassLogger();
private int _listeningPort;
private int _ApplicationReceivingPort;
private string _setupFilename;
private string _startupPath;
public ApplicationUpdater()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
init();
logger.Info("after init");
Thread ListnerThread = new Thread(new ThreadStart(StartListener));
ListnerThread.IsBackground = true;
ListnerThread.Start();
logger.Info("after thread start");
}
private void init()
{
_listeningPort = Convert.ToInt16(ConfigurationSettings.AppSettings["ListeningPort"]);
_setupFilename = ConfigurationSettings.AppSettings["SetupFilename"];
_startupPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
}
private void StartListener()
{
try
{
logger.Info("Listening Started");
ThreadPool.SetMinThreads(50, 50);
TcpListener listener = new TcpListener(_listeningPort);
listener.Start();
while (true)
{
TcpClient c = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ProcessReceivedMessage, c);
}
}
catch (Exception ex)
{
logger.Error(ex.Message);
}
}
void ProcessReceivedMessage(object c)
{
try
{
TcpClient tcpClient = c as TcpClient;
NetworkStream Networkstream = tcpClient.GetStream();
byte[] _data = new byte[1024];
int _bytesRead = 0;
_bytesRead = Networkstream.Read(_data, 0, _data.Length);
MessageContainer messageContainer = new MessageContainer();
messageContainer = SerializationManager.XmlFormatterByteArrayToObject(_data, messageContainer) as MessageContainer;
switch (messageContainer.messageType)
{
case MessageType.ApplicationUpdateMessage:
ApplicationUpdateMessage appUpdateMessage = new ApplicationUpdateMessage();
appUpdateMessage = SerializationManager.XmlFormatterByteArrayToObject(messageContainer.messageContnet, appUpdateMessage) as ApplicationUpdateMessage;
Func<ApplicationUpdateMessage, bool> HandleUpdateRequestMethod = HandleUpdateRequest;
IAsyncResult cookie = HandleUpdateRequestMethod.BeginInvoke(appUpdateMessage, null, null);
bool WorkerThread = HandleUpdateRequestMethod.EndInvoke(cookie);
break;
}
}
catch (Exception ex)
{
logger.Error(ex.Message);
}
}
private bool HandleUpdateRequest(ApplicationUpdateMessage appUpdateMessage)
{
try
{
TcpClient tcpClient = new TcpClient();
NetworkStream networkStream;
FileStream fileStream = null;
tcpClient.Connect(appUpdateMessage.receiverIpAddress, appUpdateMessage.receiverPortNumber);
networkStream = tcpClient.GetStream();
fileStream = new FileStream(_startupPath + "\\" + _setupFilename, FileMode.Open, FileAccess.Read);
FileInfo fi = new FileInfo(_startupPath + "\\" + _setupFilename);
BinaryReader binFile = new BinaryReader(fileStream);
FileUpdateMessage fileUpdateMessage = new FileUpdateMessage();
fileUpdateMessage.fileName = fi.Name;
fileUpdateMessage.fileSize = fi.Length;
MessageContainer messageContainer = new MessageContainer();
messageContainer.messageType = MessageType.FileProperties;
messageContainer.messageContnet = SerializationManager.XmlFormatterObjectToByteArray(fileUpdateMessage);
byte[] messageByte = SerializationManager.XmlFormatterObjectToByteArray(messageContainer);
networkStream.Write(messageByte, 0, messageByte.Length);
int bytesSize = 0;
byte[] downBuffer = new byte[2048];
while ((bytesSize = fileStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
networkStream.Write(downBuffer, 0, bytesSize);
}
fileStream.Close();
tcpClient.Close();
networkStream.Close();
return true;
}
catch (Exception ex)
{
logger.Info(ex.Message);
return false;
}
finally
{
}
}
protected override void OnStop()
{
}
}
I have to note something that my windows service (server) is multithreaded.
On the receiving end, set up a while loop to listen until there's no more data, then exit gracefully: close the stream and client. The framework TCP libs consider it an issue to drop a connection cold on thread exit and will therefore throw the exception you're seeing.
This will also save you from an intermittent problem you'll likely see once you correct the current one: Stream.Read with a length specifier won't always give you your full buffer each time. It looks like you're sending (up to) 2kb chunks and receiving into a (single-shot) 1kb buffer anyhow so you may start to get XML exceptions as well.
If that's not enough detail, ask and I'll dig up some old TcpClient code.