I am very new to programming c# in visual studio. I am trying to send a message from an android app (Client side) to a windows app (Server side) using sockets. I don't know if I should be able to do it in the wireless network that I have, or is that even the problem. Also can I pick and use any port number or it has to be a specific number that I have to fetch from somewhere? I will post both my client and server codes, and the output of my server side code. Any help is much appreciated.
Client:
public class MainActivity extends Activity {
private EditText editTxt;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.button1);
editTxt = (EditText) findViewById(R.id.editText1);
final String str = editTxt.getText().toString();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
connectSocket(str);
}
});
}
private void connectSocket(String a){
new Thread( new Runnable() {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName("10.5.5.117");
Log.d("TCP", "C: Connecting...");
Socket socket = new Socket(serverAddr, 5555);
String message = "1";
PrintWriter out = null;
BufferedReader in = null;
try {
Log.d("TCP", "C: Sending: '" + message + "'");
out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println(message);
String text = "";
String finalText = "";
while ((text = in.readLine()) != null) {
finalText += text;
}
editTxt.setText(finalText);
Log.d("TCP", "C: Sent.");
Log.d("TCP", "C: Done.");
} catch(Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
socket.close();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
Log.e("TCP", "C: UnknownHostException", e);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("TCP", "C: IOException", e);
e.printStackTrace();
}
}}).start();
}
}
Server:
namespace WindowsSocketServer
{
public class serv
{
public static void Main()
{
try
{
IPAddress ipAd = IPAddress.Parse("10.5.5.117");
// use local m/c IP address, and
// use the same in the client
// Initializes the Listener
TcpListener myList = new TcpListener(ipAd, 5555);
// Start Listeneting at the specified port
myList.Start();
Console.WriteLine("The server is running at port 5555...");
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint);
Console.WriteLine("Waiting for a connection.....");
m:
Socket s = myList.AcceptSocket();
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
byte[] b = new byte[100];
int k = s.Receive(b);
char cc = ' ';
string test = null;
Console.WriteLine("Recieved...");
for (int i = 0; i < k - 1; i++)
{
Console.Write(Convert.ToChar(b[i]));
cc = Convert.ToChar(b[i]);
test += cc.ToString();
}
switch (test)
{
case "1":
break;
}
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\nSent Acknowledgement");
s.Close();
// clean up
goto m;
s.Close();
myList.Stop();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
}
Server Output:
The thread 'vshost.NotifyLoad' (0x21e8) has exited with code 0 (0x0).
The thread '<No Name>' (0x1d04) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x2448) has exited with code 0 (0x0).
'WindowsSocketServer.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Projects\Offline\WindowsSocketServer\bin\Debug\WindowsSocketServer.exe', Symbols loaded.
'WindowsSocketServer.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50 a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Error..... at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)
at System.Net.Sockets.TcpListener.Start()
at WindowsSocketServer.serv.Main() in
C:\Projects\Offline\WindowsSocketServer\Program.cs:line 27
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
The thread 'vshost.RunParkingWindow' (0x1a5c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1ba4) has exited with code 0 (0x0).
The program '[8828] WindowsSocketServer.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
You should be able to get more information from the SocketException as to what the problem is. (Description, error code etc). I'm guessing that it breaking on Bind can simply be explained by port 5555 being already in use by another application (adb perhaps?). Usually only one application can listen on a given port, so try a different one. You can pick any port (< 1024 are reserved ports, but any above that up to 65535 are valid). Just update the client to connect to the new port too.
Related
I'm working on two programs, one software Microsoft visual studio 2010 when I run a server and a second program : Eclipse ADT (ANDROID device development environment) in which I supposedly client. The goal is to establish a connection between SERVER in C# and Android CLIENT. It should not be a problem, I tried on TCP and UDP tried on, it falls on both object creation context (in TCP that falls on the object socket and UDP SOCKET falls DATAGRAM object creation), it seems to me the problem is: activitythread.performlaunchactivity (activitythread $ activityclientreco rd intent) line 2247
As I understand the problem is not in my code snippet but the SOCKET supplementation with software built into Eclipse, I tried to re-install, add the latest plugin. To your next question, I did permissions for Android device and internet. This I have no idea how to approach this problem which I am going for a month or more ..
In addition I'll add my code in android client :
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.util.Log;
public class MainActivity extends Activity {
private TextView txt;
private Button b;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button)findViewById(R.id.button1);
txt = (TextView)findViewById(R.id.textView1);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
connectSocket("Hello");
}
});
}
private void connectSocket(String a){
try {
InetAddress serverAddr = InetAddress.getByName("10.0.0.8");
Log.d("TCP", "C: Connecting...");
**Socket socket = new Socket(serverAddr, 4444);**
String message = "1";
PrintWriter out = null;
BufferedReader in = null;
try {
Log.d("TCP", "C: Sending: '" + message + "'");
out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println(message);
while ((in.readLine()) != null) {
txt.append(in.readLine());
}
Log.d("TCP", "C: Sent.");
Log.d("TCP", "C: Done.");
} catch(Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
socket.close();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
Log.e("TCP", "C: UnknownHostException", e);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("TCP", "C: IOException", e);
e.printStackTrace();
}
}
}
and my server in C# :
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
public class TestTCP
{
public static void Main()
{
try
{
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
// use local m/c IP address, and
// use the same in the client
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, 11000);
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("The server is running at port 11000...");
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint);
Console.WriteLine("Waiting for a connection.....");
m:
Socket s = myList.AcceptSocket();
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
byte[] b = new byte[100];
int k = s.Receive(b);
char cc = ' ';
string test = null;
Console.WriteLine("Recieved...");
for (int i = 0; i < k - 1; i++)
{
Console.Write(Convert.ToChar(b[i]));
cc = Convert.ToChar(b[i]);
test += cc.ToString();
}
switch (test)
{
case "1":
break;
}
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\nSent Acknowledgement");
/* clean up */
goto m;
s.Close();
myList.Stop();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
Thanks.
First of all you may not run the connecSocket method in your UI thread. You have to do something like this:
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Thread stackOverflow = new Thread(new Runnable() {
#Override
public void run() {
connectSocket("Hello");
}});
stackOverflow.start();
}
});
Otherwise you get this exception:
android.os.NetworkOnMainThreadException
Secondly you must connect to the same port and interface where your server is listening:
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
Should be the same address as the one you are using in your Android application:
IPAddress ipAd = IPAddress.Parse("10.0.0.8");
And your Android application must connect to the same port where server is listening:
Socket socket = new Socket(serverAddr, 11000);
Finally do not forget the Android permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
And be careful with firewalls and things like that, they could also drop your connections.
i am new to this website but have been reading alot since long.
I am little confused with this IP stuff, i am reasonable programmer but very poor at IP thing.
I want to implement C# client with Android Server[Android device moves around the world so first thing is to get its IP address].
I have written[copied] following android code from stackOverflow question and trying to use it.
public static String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
String ip = Formatter.formatIpAddress(inetAddress.hashCode());
Log.i("IP", "***** IP="+ ip);
return ip;
}
}
}
} catch (SocketException ex) {
Log.e("EXCPTN", ex.toString());
}
return null;
}
Question 1: It gives me some Ip lets say 142.171.13.206 , but when i check my Ip by googling 'what is my ip' from my andoird decide, i totally get new IP [120.100.78.14]. What wrong i am doing? I am running on Wifi, no edge no 3g or something.
Question 2: If i have a C# client, which android IP should i try to connect ? Becuase i am unable to connect to android server.
My C# Client code is something like this
try
{
const int Port = 4321;
TcpClient ourMagicClient = new TcpClient();
//Connect to the server - change this IP address to match your server's IP!
ourMagicClient.Connect("192.177.111.200", Port);
//Use a NetworkStream object to send and/or receive some data
NetworkStream ourStream = ourMagicClient.GetStream();
//Let's set up some data!
byte[] data = Encoding.ASCII.GetBytes("Plz recieve this msg!");
//Everyone ready? Send that bad-boy!
ourStream.Write(data, 0, data.Length); //Start at the 0'th position in our string and send until the end of the string, but we can stop there...
}
catch (Exception ex)
{
textBox1.Text = ex.ToString();
}
And finally here is the code for my android listener running 4.4 Kitkat
private class SocketServerThread extends Thread {
static final int SocketServerPORT = 4321;
int count = 0;
#Override
public void run() {
try {
serverSocket = new ServerSocket(SocketServerPORT);
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
info.setText("I'm waiting here: "
+ serverSocket.getLocalPort());
;
}
});
while (true) {
Socket socket = serverSocket.accept();
count++;
message += "#" + count + " from " + socket.getInetAddress()
+ ":" + socket.getPort() + "\n";
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(
socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String msgReply = "Hello from Android, you are #" + cnt;
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.close();
message += "replayed: " + msgReply + "\n";
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
}
}
I have googles alot, searched this website too, but i am unable to connect C# client with Andoird server. Plz help me with the code what n where to fix. Or if you have totally different working code plz share that with me.
Note: Thx to all those from which i have copied above code [unfortunately i dont have referece to thier websites]. Thx!
I have problems with bluetooth connection. It is endless connection and after several seconds it is always hangs up on ReadAsync with information:
The thread 0x19c has exited with code 259 (0x103).
The program '[5612] TaskHost.exe' has exited with code 0 (0x0).
After this - connection is still valid with device (I see connection diode on device), but there is no chance to:
1) Connect again to device (connection is still present)
2) Receive any data from socket/connection
It is allways hanging here:
returnedBuffer =
await
socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length,
InputStreamOptions.Partial);
Modyfied code is from 32feet sample:
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
var bdp = new BluetoothDevicePicker();
PeerInformation pi = await bdp.PickDeviceAsync();
if (pi != null)
{
var hn = new HostName(pi.HostName.RawName);
// do something with the device
ReadThread(hn);
}
}
private async void ReadThread(object host)
{
reading = true;
var socket = new StreamSocket();
socket.Control.KeepAlive = true;
socket.Control.NoDelay = false;
//socket.Control.QualityOfService = SocketQualityOfService.LowLatency;
IAsyncAction a = StreamSocketExtensions.ConnectAsync(socket, (HostName)host, RfcommServiceId.SerialPort);
await a;
var buffer = new byte[2048];
while (reading)
{
IBuffer returnedBuffer = null;
try
{
returnedBuffer =
await
socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length,
InputStreamOptions.Partial);
if (returnedBuffer != null)
{
string s = PrintByteArray(returnedBuffer.ToArray(), (int)returnedBuffer.Length);
if (!string.IsNullOrEmpty(s))
{
Dispatcher.BeginInvoke(new Action<string>(InsertMessage), s);
}
}
}
catch
{
}
}
socket.Dispose();
}
Do 3 chunks sent by 3 calls to Linux 'C' write(), through TCP, get received as the same, 3 chunks by Windows C# .BeginReceive(), or a single, contiguous chunk, or however many have been received when .BeginReceived is called?
A 'C' app on Linux sends a message by 3 calls to write(), through TCP connection, to a Windows C# app, which receives using BeginReceive().
Does BeginReceive() need to be called three times, to receive each of the three chunks sent by write()? Or is the size received by BeginReceive() equal to the size of what Windows has received when BeginReceive() is called? Which could be all bytes sent by the 3 writes(), or a partial amount, so .BeginReceive() should be called UNTIL all are received?
The Linux C app is running on an embedded TI ARM, and inside the same box the Windows C# app is running a Single Board Computer. The ARM has a direct Ethernet connection to the SBC.
The communication between the ARM and SBC sometimes fails to start at boot time, and I'm reverse engineering the source code to check for bad design.
ARM side is TCP listener, and Windows client initiates the TCP connection.
Using MontaVista(R) Linux(R) Professional Edition 5.0.0 (0702774)
and Windows-7 Visual-Studio 2010 Visual-C#.
Here is the ARM sending software, and the Windows receiving software........................
LINX 'C'
char msgBuffer[64];
sprintf(msgBuffer, START_MSG_ENVELOPE, msgId++, ack);
write(connection->fd, msgBuffer, strlen(msgBuffer));
write(connection->fd, msg, strlen(msg));
write(connection->fd, END_MSG_ENVELOPE, strlen(END_MSG_ENVELOPE));
HERE IS THE WINDOWS C# SIDE OF IT.............................................
private static void makeConnection(Socket clientSocket, int iPortNo)
{
TimeoutObject.Reset();
socketexception = null;
IPAddress ip;
//create the end point
IPEndPoint ipEndPoint;
ip = IPAddress.Parse(ipAddress);
try
{
ipEndPoint = new IPEndPoint(ip, iPortNo);
//connect to the remote host...
clientSocket.BeginConnect(ip, iPortNo, new AsyncCallback(CallBackMethod), clientSocket);
if (TimeoutObject.WaitOne(5 * 1000, false)) //5 secs connection timeout
{
if (!IsConnectionSuccessful)
{
string msg = VNResourceManager.Instance.GetString(VNMessages.DAM_NOT_FOUND);
if (socketexception != null)
msg += ": " + socketexception.Message;
throw new Exception(msg);
}
}
else
{
clientSocket.Close();
throw new TimeoutException(VNResourceManager.Instance.GetString(VNMessages.CONNECTION_TO_DAM_TIMED_OUT));
}
//watch for data ( asynchronously )...
WaitForData();
}
catch (SocketException e)
{
socketexception = e;
throw;
}
}
private static void CallBackMethod(IAsyncResult asyncresult)
{
try
{
IsConnectionSuccessful = false;
Socket socket = asyncresult.AsyncState as Socket;
if (socket.Connected)
{
socket.EndConnect(asyncresult);
IsConnectionSuccessful = true;
}
}
catch (Exception ex)
{
IsConnectionSuccessful = false;
socketexception = ex;
}
finally
{
TimeoutObject.Set();
}
}
public static void WaitForData()
{
try
{
if (asyncCallBack == null)
{
asyncCallBack = new AsyncCallback(OnDataReceived);
}
CSocketPacket theSocPkt = new CSocketPacket();
theSocPkt.thisSocket = clientSocket;
asyncResult = clientSocket.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, asyncCallBack, theSocPkt);
}
catch (SocketException se)
{
notifyErrorEventSubscribers(se);
}
}
public static void send(string message)
{
try
{
byte[] byData = System.Text.Encoding.ASCII.GetBytes(message);
clientSocket.Send(byData);
}
catch (SocketException se)
{
notifyErrorEventSubscribers(se);
throw;
}
}
//[MethodImpl(MethodImplOptions.Synchronized)]
public static void OnDataReceived(IAsyncResult result)
{
try
{
CSocketPacket theSockId = (CSocketPacket)result.AsyncState;
//end receive...
int messageSize = 0;
messageSize = theSockId.thisSocket.EndReceive(result);
Console.WriteLine(">>>>>>>>> messageSize = " + messageSize); // !!!
char[] chars = new char[messageSize + 1];
System.Text.Decoder d = System.Text.Encoding.ASCII.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, messageSize, chars, 0);
string replyMessage = new System.String(chars);
lock (syncLock) //LastIndexOf function accesses the current culture info and we clear it in WM_TIMECHANGE handler (protecting from that race condition here)
{
if (replyMessage.LastIndexOf("\0") > 0)
replyMessage = replyMessage.Remove(replyMessage.LastIndexOf("\0"), 1);
if (replyMessage.LastIndexOf(Terminator) > 0)
replyMessage = replyMessage.Remove(replyMessage.LastIndexOf(Terminator), 1);
}
// Continue the waiting for data on the Socket
WaitForData();
receivedMsg += replyMessage;
// only serialize when we feel we have a message or we have reached the message line limit
if (((receivedMsg.Contains("message") && receivedMsg.Contains("/>")) || receivedMsg.Contains("</message>")) /* || (mRecvdMsgLineCount == Message.kMaxLines) */ )
{
List<XmlMessage> msgList = new List<XmlMessage>();
int index = -1;
do
{
index = receivedMsg.IndexOf("</message>");
if (index != -1)
{
XmlMessage message;
string strMessage = receivedMsg.Substring(0, index + "</message>".Length);
//MessageBox.Show(strMessage);
strMessage = strMessage.TrimStart(new char[] { '\r', '\n' });
receivedMsg = receivedMsg.Remove(0, index + "</message>".Length);
try
{
message = (XmlMessage)XmlMessage.GetXmlSerializer().Deserialize(XmlReader.Create(new StringReader(strMessage)));
}
catch (InvalidOperationException error)
{
string strErrorMessage = error.Message;
if (error.InnerException != null)
strErrorMessage += "\r\n" + error.InnerException.Message;
notifyErrorEventSubscribers(new Exception(strErrorMessage + "\r\n-----------------------------------------------------------------\r\n" + strMessage));
return;
}
msgList.Add(message);
}
} while (index != -1);
StringWriter sw = new StringWriter();
string serializedXml = string.Empty;
string strXmlMessage = string.Empty;
foreach (XmlMessage message in msgList)
{
if (message.ack_required && (message.update == null))
{
XmlMessage messageAcknowledge = new XmlMessage();
messageAcknowledge.ack_required = false;
messageAcknowledge.ack = new ack();
messageAcknowledge.ack.success = true;
messageAcknowledge.ack.id = message.id;
try
{
sendMessage(messageAcknowledge);
}
catch(Exception ex)
{
Logger.Log(EnumLoggingLevel.Error, "SocketCommunicationXMl.OnDataReceived", ex.Message);
}
}
if (dataReceivedEvent != null)
{
dataReceivedEvent(new object(), new DataReceivedEventArgs(message));
}
if ((ackRequiredMsg != null) && (message.ack != null))
{
if ((message.ack.id == ackRequiredMsg.id) && message.ack.success)
{
eventWaitForAck.Set();
}
}
}
}
}
catch (ObjectDisposedException objectDisposedException)
{
// Dispatcher.dispatchDebug(Debug.Level_3,"Socket has been closed", this);
notifyErrorEventSubscribers(objectDisposedException);
}
catch (SocketException se)
{
if (se.ErrorCode == 10054)
{
/*
for (int i = 0; i < 50; i++)
{
Thread.Sleep(1000);
}
try
{
SocketCommunicationDaq.Reconnect();
}
catch(Exception ex)
{
VNMsgBox.Show(ex.Message, MsgButtonType.OkOnly, MsgIconType.Error);
return;
}
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
for (int i = 0; i < 3; i++)
{
try
{
connect();
break;
}
catch (Exception ex)
{
System.Threading.Thread.Sleep(5000);
}
}
*/
Logger.Log(EnumLoggingLevel.Error, "OnDataReceived: ", se.ToString());
}
else
{
notifyErrorEventSubscribers(se);
}
}
}
As others have mentioned, TCP is a streaming protocol, so you never can tell how many DataReceived callbacks it will take to get all 100 bytes. Could be 1, could be 100.
The receive code is fairly complex and performance could be improved (too many string operations). Hard to tell if there are control-flow issues. I would suggest breaking the DataReceived method up to simplify. Here's a reasonable skeleton:
public static void OnDataReceived(IAsyncResult result)
{
//1) copy all data received into a buffer of some sort, like MemoryStream
//2) Dispatch any/all full messages that have been received
// to a queue or handler method (maybe handle on another thread)
//(hold onto any leftover bytes received that are part of the next message)
//Call BeginReceive() again
}
Also, it can help simplify Framing if you use a Length-Prefixed message format.
As #nos already stated, number of receives does not equal the number of sends, regardless of the client application was written in.
See also When does TcpClient's NetworkStream finish one read operation?
When a client disconnects, the server closes. Tell me how to leave the ability to connect new customers after the close of the first session .Thanks in advance.
namespace tcpserver
{
class Program
{
static void Main(string[] args)
{
string cmd;
int port = 56568;
Server Serv = new Server(); // Создаем новый экземпляр класса
// сервера
Serv.Create(port);
while (true)
{
cmd = Console.ReadLine(); // Ждем фразы EXIT когда
// понадобится выйти из приложения.
// типа интерактивность.
if (cmd == "EXIT")
{
Serv.Close(); // раз выход – значит выход. Серв-нах.
return;
}
}
//while (Serv.Close() == true) { Serv.Create(port); }
}
public class Server // класс сервера.
{
private int LocalPort;
private Thread ServThread; // экземпляр потока
TcpListener Listener; // листенер))))
public void Create(int port)
{
LocalPort = port;
ServThread = new Thread(new ThreadStart(ServStart));
ServThread.Start(); // запустили поток. Стартовая функция –
// ServStart, как видно выше
}
public void Close() // Закрыть серв?
{
Listener.Stop();
ServThread.Abort();
return;
}
private void ServStart()
{
Socket ClientSock; // сокет для обмена данными.
string data;
byte[] cldata = new byte[1024]; // буфер данных
Listener = new TcpListener(LocalPort);
Listener.Start(); // начали слушать
Console.WriteLine("Waiting connections on " + Convert.ToString(LocalPort) + " port");
try
{
ClientSock = Listener.AcceptSocket(); // пробуем принять клиента
}
catch
{
ServThread.Abort(); // нет – жаль(
return;
}
int i = 0;
if (ClientSock.Connected)
{
while (true)
{
try
{
i = ClientSock.Receive(cldata); // попытка чтения
// данных
}
catch
{
}
try
{
if (i > 0)
{
data = Encoding.ASCII.GetString(cldata).Trim();
Console.WriteLine("<" + data);
if (data == "CLOSE") // если CLOSE –
// вырубимся
{
ClientSock.Send(Encoding.ASCII.GetBytes("Closing the server..."));
ClientSock.Close();
Listener.Stop();
Console.WriteLine("Server closed. Reason: client wish! Type EXIT to quit the application.");
ServThread.Abort();
return;
}
else
{ // нет – шлем данные взад.
ClientSock.Send(Encoding.ASCII.GetBytes("Your data: " + data));
}
}
}
catch
{
ClientSock.Close(); //
Listener.Stop();
Console.WriteLine("Client disconnected. Server closed.");
ServThread.Abort();
}
}
}
}
}
}
}
Typical threaded server code will read more like this (in a pseudo code, because I don't know enough Java details to write it exactly, and because C is a bit stifling):
socket s = new socket
bind s to an optional IP, port
listen s
while true
cli = accept s
t = new thread(handle_client, cli)
maybe disown thread, so no need to join it later
t.start
The important point is that creating the socket, binding it to an address, and listen are all handled outside the loop, and accept() and starting threads are inside the loop.
You may want to wrap this entire block inside another thread; that is acceptable. The important part is separating the listen from the accept and per-client thread. This allows your code to stop accepting new connections but handle existing clients until they disconnect, or disconnect existing connections when they use their allotment of resources but continue accepting connections, etc. (Note how your last catch block will terminate the server if any single client socket throws an exception; that kind of code is easy to avoid with the usual server layout.)
replace
ServThread.Abort();
return;
with a continue instead, this will not break the while loop and yet stop the current "round". Please consider reading this: http://www.codeproject.com/KB/IP/serversocket.aspx nice project to build from