I using this kind of code to work with some server:
int port = 6789;
string serverAddress = "127.0.0.1";
string playersName = "random";
TcpClient client = null;
StreamWriter writer = null;
StreamReader reader = null;
try
{
client = new TcpClient();
client.Connect(serverAddress, port);
NetworkStream stream = client.GetStream();
writer = new StreamWriter(stream);
writer.Write("100 " + playersName + "\r\n");
writer.Flush();
reader = new StreamReader(stream);
bool isRunning = true;
while (isRunning)
{
string msg = reader.ReadLine(); //stack in this line
string[] parts = msg.Split(' ');
...
}
}
I've no exception, but my application stack in line with string msg = reader.ReadLine(); and doesn't work. Connection to server is good and work, because server write message that my client app was accesing connection.
Your reading method is unsafe. Here is the signature of StreamReader.ReadLine method:
//
// Summary:
// Reads a line of characters from the current stream and returns the data as
// a string.
//
// Returns:
// The next line from the input stream, or null if the end of the input stream
// is reached.
//
// Exceptions:
// System.OutOfMemoryException:
// There is insufficient memory to allocate a buffer for the returned string.
//
// System.IO.IOException:
// An I/O error occurs.
public override string ReadLine();
First of all, it can (and must) return null and you'll get NullReferenceException next line.
Reading data from network is not trivial thing. Luckily, it was discussed many times:
What is the correct way to read from NetworkStream in .NET
Ensure streamreader doesn't hang waiting for data
TCPClient not reading the incoming data
Related
I'm trying to build a checker via .NET using TCPCLIENT
For each email to check my app is making a connection between my server and the smtp server which means sometimes the smtp server dont response.
The question that im looking for is how to keep retrying to connect
if the connection missed .
Here is my code :
TcpClient tClient = new TcpClient("smtp-in.orange.fr", 25);
string CRLF = "\r\n";
byte[] dataBuffer;
string ResponseString;
NetworkStream netStream = tClient.GetStream();
StreamReader reader = new StreamReader(netStream);
ResponseString = reader.ReadLine();
/* Perform HELO to SMTP Server and get Response */
dataBuffer = BytesFromString("HELO KirtanHere" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
dataBuffer = BytesFromString("mail from:<contact#contact.com>" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
Seems you need to implement try catch block inside for loop.
for (var i = 0; i < retryCount; i++)
{
try
{
YourAction();
break; // success
}
catch { /*ignored*/ }
// give a little breath..
Thread.Sleep(50);
}
Looks ugly but pretty simple, and for some cases it is not recommended. You may want to try Polly, this library allows you to express exception handling policies including Retry.
And also I want to point out that you've had never dispose disposable objects such as NetworkStream and StreamReader. Since you will run long running process, you should dispose them.
private static void YourAction()
{
var tClient = new TcpClient("smtp-in.orange.fr", 25);
const string CRLF = "\r\n";
string ResponseString;
using (var netStream = tClient.GetStream())
using (var reader = new StreamReader(netStream))
{
ResponseString = reader.ReadLine();
/* Perform HELO to SMTP Server and get Response */
var dataBuffer = BytesFromString("HELO KirtanHere" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
dataBuffer = BytesFromString("mail from:<contact#contact.com>" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
}
}
One Solution would be to use Polly library.
With Polly you need to configure Policy as in which scenarios, you want to retry.
Please specify you exception Policy something like below
var maxRetryAttempts = 3;
var pauseBetweenFailures = TimeSpan.FromSeconds(2);
var retryPolicy = Policy
.Handle<Exception>()// Handle specific exception
.WaitAndRetryAsync(maxRetryAttempts, i => pauseBetweenFailures);
Surround your code with
await retryPolicy.ExecuteAsync(async () =>
{
TcpClient tClient = new TcpClient("smtp-in.orange.fr", 25);
string CRLF = "\r\n";
byte[] dataBuffer;
.....
});
For detailed explanation on how to use Polly, there is nice article ..
https://alastaircrabtree.com/implementing-the-retry-pattern-using-polly/
I've been creating a TCPClient which is suppose to connect to a server but am getting this error:
System.InvalidOperationException: 'The operation is not allowed on
non-connected sockets.'
Here's my Code:
Public String IPAddress = "192.168.100.xxx"
Public Int32 Port = 23;
public TcpClient client = new TcpClient();
public void Connect() {
client.Connect(IPAddress, Port);
// send first message request to server
Byte[] msg_data = System.Text.Encoding.ASCII.GetBytes("Hello Server);
// uses the GetStream public method to return the NetworkStream
NetworkStream netStream = _client.GetStream();
// write message to the network
netStream.Write(msg_data, 0, msg_data.Length);
// buffer to store the response bytes
msg_data = new Byte[256];
// read the first batch of response byte from arduino server
Int32 bytes = netStream.Read(msg_data, 0, msg_data.Length);
received_msg = System.Text.Encoding.ASCII.GetString(msg_data, 0, bytes);
netStream.Close();
}
public void Send() {
// message data byes to be sent to server
Byte[] msg_data = System.Text.Encoding.ASCII.GetBytes(_sendMessage);
// uses the GetStream public method to return the NetworkStream
// ** Error Here: System.InvalidOperationException: 'The operation is not allowed on non-connected sockets.'
NetworkStream netStream = client.GetStream();
// write message to the network
netStream.Write(msg_data, 0, msg_data.Length);
// buffer to store the response bytes
msg_data = new Byte[256];
// read the first batch of response byte from arduino server
Int32 bytes = netStream.Read(msg_data, 0, msg_data.Length);
received_msg = System.Text.Encoding.ASCII.GetString(msg_data, 0, bytes);
netStream.Close(); // close Stream
}
I am getting and error when creating a new instance of NetworkStream netStream = client.GetStream();. Been struggling to find whats causing the error, I think it's somehow closing the connection above.
Everything is in a class and must be called at anyplace in the software.
client.GetStream() is implemented like:
return new NetworkStream(this.Client, true);
whereas the true means if the stream is disposed/closed it also closes/disconnects the socket/client. You should be able to avoid this by directly calling
var netStream = new NetworkStream(client.Client, false);
And even better would be instead of:
NetworkStream netStream = client.GetStream();
…
netSteam.Dlose();
to ensure that the stream is always closed even if an errors by writing:
using (var netStream = new NetworkStream(client.Client, false))
{
…
}
I try to realize simple mail client. Now I can retriev messages:
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER my_mail#gmail.com");
// sent to server
sw.Flush();
sw.WriteLine("PASS my_pass");
sw.Flush();
// this will retrive your first email
sw.WriteLine("RETR 1");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == ".")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
//str = reader.ReadToEnd();
// close the connection
sw.WriteLine("QUIT");
sw.Flush();
richTextBox2.Text = str;
But when I try to realize operations STAT and LIST my programm crashes. I think there is a problem in cycle of reading streams. For operation STAT I try to read until "\r\n" (strTemp = "\r\n") and for operation LIST - ".\r\n" respectively.
This is my code for STAT:
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER my_mail#gmail.com");
// sent to server
sw.Flush();
sw.WriteLine("PASS my_pass");
sw.Flush();
// this will retrive your first email
sw.WriteLine("STAT");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == "\r\n")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
//str = reader.ReadToEnd();
// close the connection
sw.WriteLine("QUIT");
sw.Flush();
richTextBox2.Text = str;
After I press the button my main window is not responding. Where is my mistake?
Thank you!
Your app is most likely hung on ReadLine(). Note that StreamReader.ReadLine() does not include the \r\n. So your check for \r\n will never hit, hence that break statement will never hit.
You may simply need to change it to if (strTemp == ""). If that doesn't do the trick, you'll have to step through in the debugger.
Also note that blocking calls like this are not a good idea in the UI thread. You really should offload this to a background worker.
I have written this code to check for a particular string from a file. Right now it checks for the string. But how can I send the reply back saying "it is present" to the client? The server side program should have all the codes. It also accepts multiple clients.
The Procedure of this program is as follows
Basically if a client wants to check if there's a particular string(word) in a file, he connects this code through a port on telnet. He types in the strings he wants to search(on telnet) and send it to the server side. And this server side program checks it for him from the file. And if it is present, it sends a message back to the client saying "The string is present in the file" And if it isn't, It should send a message saying "It is not".
The search string("hello") is in this program. How can I enable the client to search for it from client side(telnet)?
This is where I've come till with a lot of help and tutorials. Can someone please help me?
EDITED - I have changed the code such that it sends a reply back to the client. All I need to know now is, how can I enable the client to search (type the word he wants to search for) through the client side(telnet)? Any help will be really appreciated.
I have updated my code too.
Thank you.
class Program
{
static void Main(string[] args)
{
IPAddress ipad = IPAddress.Parse("127.0.0.1");
TcpListener serversocket = new TcpListener(ipad, 8888);
TcpClient clientsocket = default(TcpClient);
Byte[] bytes = new Byte[256];
serversocket.Start();
Console.WriteLine(">> Server Started");
while(true)
{
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accepted Connection From Client");
LineMatcher lm = new LineMatcher(clientsocket);
Thread thread = new Thread(new ThreadStart(lm.Run));
thread.Start();
Console.WriteLine("Client connected");
}
Console.WriteLine(" >> exit");
Console.ReadLine();
clientsocket.Close();
serversocket.Stop();
}
}
public class LineMatcher
{
public string fileName = "c:/myfile2.txt";
private TcpClient _client;
public LineMatcher(TcpClient client)
{
_client = client;
}
public void Run()
{
byte[] data = new byte[256];
NetworkStream strm = _client.GetStream();
try
{
using (var r = new StreamReader("c:/myfile2.txt"))
{
string line = "";
bool done = false;
int lineNumber = 0;
String s = r.ReadToEnd();
ASCIIEncoding encoder = new ASCIIEncoding();
while (String.IsNullOrEmpty(s))
{
data = encoder.GetBytes("There is no data in the file.");
Console.WriteLine("There is no data in the file.");
}
if (s.IndexOf("hello", StringComparison.CurrentCultureIgnoreCase) >= 0)
{
data = encoder.GetBytes("It is Present.");
}
else
{
data = encoder.GetBytes("It is not Present");
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
strm.Write(data, 0, data.Length);
strm.Flush();
Console.WriteLine("Closing client");
_client.Close();
}
}
Instead of if (s==null), you should check if the string contains the word. Being very creative, we can check for the word "word" like so: if (s.IndexOf("word") >= 0) which searches for the location of "word" within s and returns the index. In C#, indexes always start at 0. If the string "word" is not contained within your file string, it will return -1. Therefore that if statement will return true if the word is contained, or false if it is not.
Think of if as a statement which takes only one parameter. And that parameter is either true or false. The (s==null) is an expression which returns the value true or false which is then used by the if statement.
However, this will not work, if for instance, the file reads: THIS IS A WORD, because "word" does not equal "WORD". You can get around this by using a case insensitive compare like so:
if(s.IndexOf("word", StringComparison.CurrentCultureIgnoreCase) >= 0) {
// contains "word"
} else {
// does not contain "word"
}
Have a look at the following for reference
http://msdn.microsoft.com/en-us/library/ms228362(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/system.string.aspx
Your client applications will only be able to search once. This is because after you perform the search, you close the connection.
Console.WriteLine("Closing client");
_client.Close();
If you want the connection to stay open you will need to include a loop to ensure you return to the beginning of the LineMatcher class to re-search.
Rather than checking the IndexOf this string, I'd instead simply use the Contains method. While IndexOf is designed to find where a substring is located within a string, Contains is built for the specific purpose of simply checking whether or not a substring exists. Note that this is not case insensitive.
else if (s.Contains("HTTP"))
{
I would strongly recommend you get the searching application working first, as a stand-alone application, and then write a telnet server which launches your original application. These are two separate functions, and you'll find it a lot easier to test them individually.
I solved it. :) This is how I did it. Any suggestions on improving it?
namespace ServerSideApplication
{
class Program
{
static void Main(string[] args)
{
TcpListener socketListener = new TcpListener(8888);
TcpClient netClient = default(TcpClient);
StreamReader sr;
StringBuilder sb = new StringBuilder();
socketListener.Start();
sr = new StreamReader("c:\\test.txt");
sb.Append(sr.ReadToEnd());
while (true)
{
netClient = socketListener.AcceptTcpClient();
Console.WriteLine("Accepted Connection From Client" + Environment.NewLine + "Client connected");
ServerSide ss = new ServerSide();
ss.startServerSide(netClient, sb);
}
socketListener.Stop();
}
}
class ServerSide
{
TcpClient netClient;
StringBuilder sb;
public void startServerSide(TcpClient netClient, StringBuilder sb)
{
this.netClient = netClient;
this.sb = sb;
Thread thread = new Thread(processRequest);
thread.Start();
}
private void processRequest()
{
byte[] data = new byte[4096];
int bytesRead;
NetworkStream strm = netClient.GetStream();
bytesRead = 0;
try
{
NetworkStream ns = netClient.GetStream();
string clientChar = "", s = "";
do
{
bytesRead = ns.Read(data, 0, (int)data.Length);
clientChar = Encoding.ASCII.GetString(data).Replace("\0", "");
s += clientChar;
} while (clientChar != Environment.NewLine);
s = s.Trim();
ASCIIEncoding encoder = new ASCIIEncoding();
if (String.IsNullOrEmpty(s))
{
data = encoder.GetBytes("There is no data in the file.");
Console.WriteLine("There is no data in the file.");
}
if (sb.ToString().Contains(s))
{
data = encoder.GetBytes("It Is Present In The File.");
}
else
{
data = encoder.GetBytes("It Is Not Present In The File.");
}
strm.Write(data, 0, data.Length);
strm.Flush();
Console.WriteLine("Closing client");
netClient.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
}
}
}
I've been trying to access my GMail account to retrieve the unread emails from my email account. However, I only con perform login... Anything after that doesn't work.
First of all I connect to the server, then send the login command and finally the examine command. The thing is that the responses that are receive refers only to the connection and to the login. After that, it just stops waiting for someting to read from the StreamReader.
try
{
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
//tcpclient.Connect("pop.gmail.com", 995);
tcpclient.Connect("imap.gmail.com", 993);
// This is Secure Stream // opened the connection between client and POP Server
SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("imap.gmail.com");
bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
System.IO.StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
System.IO.StreamReader reader = new StreamReader(sslstream);
sw.WriteLine("tag LOGIN user#gmail.com pass");
sw.Flush();
sw.WriteLine("tag2 EXAMINE inbox");
sw.Flush();
sw.WriteLine("tag3 LOGOUT ");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
try
{
while ((strTemp = reader.ReadLine()) != null)
{
Console.WriteLine(strTemp);
// find the . character in line
if (strTemp == ".")
{
//reader.Close();
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
//reader.Close();
break;
}
str += strTemp;
}
}
catch (Exception ex)
{
string s = ex.Message;
}
//reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I was looking for just this sort of "Hello World" example to get me started. With the help of dkarp's answers, here's my take on Miguel's example:
static void Main( string[] args ) {
try {
TcpClient tcpclient = new TcpClient();
tcpclient.Connect( "imap.gmail.com", 993 );
SslStream sslstream = new SslStream( tcpclient.GetStream() );
sslstream.AuthenticateAsClient( "imap.gmail.com" );
if ( sslstream.IsAuthenticated ) {
StreamWriter sw = new StreamWriter( sslstream );
StreamReader sr = new StreamReader( sslstream );
sw.WriteLine( "tag LOGIN user#gmail.com pass" );
sw.Flush();
ReadResponse( "tag", sr );
sw.WriteLine( "tag2 EXAMINE inbox" );
sw.Flush();
ReadResponse( "tag2", sr );
sw.WriteLine( "tag3 LOGOUT" );
sw.Flush();
ReadResponse( "tag3", sr );
}
}
catch ( Exception ex ) {
Console.WriteLine( ex.Message );
}
}
private static void ReadResponse( string tag, StreamReader sr ) {
string response;
while ( ( response = sr.ReadLine() ) != null ) {
Console.WriteLine( response );
if ( response.StartsWith( tag, StringComparison.Ordinal ) ) {
break;
}
}
}
You might look at using a canned IMAP/SSL library instead - there is one that is still active here.
This alternative is not free.
The basis for one of these has source code that might be helpful since you want to roll your own protocol handler.
Your problem is that you're expecting POP responses from an IMAP server. POP terminates fetched messages with . and responds to other commands with a line beginning with either +OK or -ERR. IMAP doesn't. You're consuming all the server responses and then hanging, waiting for something to match your POP-like response parser. If you examine the returned data, you should see the remainder of the server's responses to your (properly-formatted) requests.
There is a possibility that the server isn't sending back responses to your second and third commands. This could be because you're trying to pipeline three requests; that is, you're sending the requests without waiting for the responses. The server is obliged to allow pipelining while in the SELECTED state, but the protocol doesn't guarantee that you can pipeline commands from the NOT AUTHENTICATED state.