Related
I'm developing a .Net 4.5.2 windows TCP socket master\client messaging solution. The solution is working for the most part; however I need the server to send a response message back to the client when the send button is selected. When the connect button is selected the master does successfully send a response message back to the client. I have made numerous attempts to send the response message back to the client application from the master when the send button is selected, but I have been unable to make it work. I am looking for some help to get me moving forward again. Don’t want to keep spinning my wheels and making no progress. Thanks in advance for the help. Please find below the server and client solutions:
Server Code:
public partial class ServerForm : Form
{
private Socket serverSocket;
private Socket clientSocket; // We will only accept one socket.
private byte[] buffer;
public ServerForm()
{
InitializeComponent();
StartServer();
}
private static void ShowErrorDialog(string message)
{
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private void StartServer()
{
try
{
IPAddress ipAddress = IPAddress.Parse("192.168.1.124");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ipAddress, 4545));
serverSocket.Listen(10);
serverSocket.BeginAccept(AcceptCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void AcceptCallback(IAsyncResult AR)
{
try
{
clientSocket = serverSocket.EndAccept(AR);
buffer = new byte[clientSocket.ReceiveBufferSize];
var sendData = Encoding.ASCII.GetBytes("Hello");
clientSocket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, SendCallback, null);
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
serverSocket.BeginAccept(AcceptCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void SendCallback(IAsyncResult AR)
{
try
{
clientSocket.EndSend(AR);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
Socket current = (Socket)AR.AsyncState;
int received = clientSocket.EndReceive(AR);
if (received == 0)
{
return;
}
PersonPackage person = new PersonPackage(buffer);
SubmitPersonToDataGrid(person);
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
//Added BeginSend which answered my question. Simple enough fix. Thanks for looking...
byte[] sendData = Encoding.ASCII.GetBytes(person.Name);
clientSocket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, SendCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
Client Code:
public partial class ClientForm : Form
{
private Socket clientSocket;
private byte[] buffer;
public ClientForm()
{
InitializeComponent();
}
private static void ShowErrorDialog(string message)
{
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
int received = clientSocket.EndReceive(AR);
if (received == 0)
{
return;
}
string message = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
Invoke((Action) delegate
{
textBoxEmployee.Text = string.Empty;
textBoxEmployee.Text = "Server says: " + message + " Paul";
});
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void ConnectCallback(IAsyncResult AR)
{
try
{
clientSocket.EndConnect(AR);
UpdateControlStates(true);
buffer = new byte[clientSocket.ReceiveBufferSize];
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void SendCallback(IAsyncResult AR)
{
try
{
clientSocket.EndSend(AR);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
private void UpdateControlStates(bool toggle)
{
Invoke((Action)delegate
{
buttonSend.Enabled = toggle;
buttonConnect.Enabled = !toggle;
labelIP.Visible = textBoxAddress.Visible = !toggle;
});
}
private void buttonSend_Click(object sender, EventArgs e)
{
try
{
PersonPackage person = new PersonPackage(checkBoxMale.Checked, (ushort)numberBoxAge.Value, textBoxEmployee.Text);
byte[] buffer = person.ToByteArray();
clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
UpdateControlStates(false);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
UpdateControlStates(false);
}
}
private void buttonConnect_Click(object sender, EventArgs e)
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect to the specified host.
var endPoint = new IPEndPoint(IPAddress.Parse(textBoxAddress.Text), 4545);
clientSocket.BeginConnect(endPoint, ConnectCallback, null);
}
catch (SocketException ex)
{
ShowErrorDialog(ex.Message);
}
catch (ObjectDisposedException ex)
{
ShowErrorDialog(ex.Message);
}
}
}
Found issue. Added BeginSend to server SendCallBack method. Code has been updated and works...
I have a bunch of async methods that I want to expose via C# sockets. The general pattern in the MSDN documentaions Has the following form:
public static void StartListening()
{
...
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
...
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
...
}
public static void AcceptCallback(IAsyncResult ar)
{
...
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
...
StateObject state = (StateObject) ar.AsyncState;
...
CalculateResult(state);
...
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
...
}
So writing all this in a nice and clean form without repetition of code has been a challenge. I am thinking along these lines but have not been able to connect the dots:
public static void StartListeningMaster()
{
string ipAddress = "localhost";
IPHostEntry ipHost = Dns.GetHostEntry(ipAddress);
IPAddress address = ipHost.AddressList[0];
StartListening(50000, address, AcceptCallback1);
StartListening(50001, address, AcceptCallback2);
StartListening(50002, address, AcceptCallback3);
...
}
public static void StartListening(int port, IPAddress ipAddress,
Action<IAsyncResult> acceptCallback) {...}
public static void AcceptCallback1(IAsyncResult ar)
{
...
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback1(ReadCallback1), state);
}
...
This works fine up to this point. But to refactor it properly I would like to have one AcceptCallback method that takes as its parameter a generic ReadCallback that takes as its parameter a CalculateResult method. This way I would not have any repetition of code. However, if I modify my AcceptCallback method to take any more parameters than IAsyncResult (for example something like:
public static void StartListening(int port, IPAddress ipAddress, Action<IAsyncResult, Action<IAsyncResult>> acceptCallback) {...}
public static void AcceptCallback(IAsyncResult ar, Action<IAsyncResult> readCallback) {}
I break the AsyncCallback delegate contract.
public delegate void AsyncCallback(IAsyncResult ar);
Then I looked into extending the existing interfaces to allow the functionality. I looked into extending
public interface IAsyncResult
But that does not seem to be the right approach either. So, how do I write this code so I do not copy and paste pretty much the same code all over the place?
So the way I tackle this is by moving the basic components in to their own abstract objects. Then build upon those objects. For example, the server only needs to accept/track connections. So I would make a server object that looks something like this:
namespace MultiServerExample.Base
{
public interface IAsyncServerBase
{
void StartListening();
bool IsListening { get; }
void StopListening();
void WriteDataToAllClients(byte[] data);
}
public abstract class AsyncServerBase<TClientBase> : IAsyncServerBase
where TClientBase : IAsyncClientBase, new()
{
// implement a TcpListener to gain access to Active property
private sealed class ActiveTcpListener : TcpListener
{
public ActiveTcpListener(IPAddress localaddr, int port)
: base(localaddr, port) { }
public bool IsActive => Active;
}
// our listener object
private ActiveTcpListener Listener { get; }
// our clients
private ConcurrentDictionary<string, TClientBase> Clients { get; }
// construct with a port
public AsyncServerBase(int port)
{
Clients = new ConcurrentDictionary<string, TClientBase>();
Listener = new ActiveTcpListener(IPAddress.Any, port);
}
// virtual methods for client action
public virtual void OnClientConnected(TClientBase client) { }
public virtual void OnClientDisconnected(TClientBase client, Exception ex) { }
// start the server
public void StartListening()
{
if(!IsListening)
{
Listener.Start();
Listener.BeginAcceptTcpClient(OnAcceptedTcpClient, this);
}
}
// check if the server is running
public bool IsListening =>
Listener.IsActive;
// stop the server
public void StopListening()
{
if (IsListening)
{
Listener.Stop();
Parallel.ForEach(Clients, x => x.Value.DetachClient(null));
Clients.Clear();
}
}
// async callback for when a client wants to connect
private static void OnAcceptedTcpClient(IAsyncResult res)
{
var me = (AsyncServerBase<TClientBase>)res.AsyncState;
if (!me.IsListening) { return; }
try
{
TcpClient client = null;
try
{
client = me.Listener.EndAcceptTcpClient(res);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Warning: unable to accept client:\n{ex}");
}
if(client != null)
{
// create a new client
var t = new TClientBase();
// set up error callbacks
t.Error += me.OnClientBaseError;
// notify client we have attached
t.AttachClient(client);
// track the client
me.Clients[t.Id] = t;
// notify we have a new connection
me.OnClientConnected(t);
}
}
finally
{
// if we are still listening, wait for another connection
if(me.IsListening)
{
me.Listener.BeginAcceptSocket(OnAcceptedTcpClient, me);
}
}
}
// Event callback from a client that an error has occurred
private void OnClientBaseError(object sender, AsyncClientBaseErrorEventArgs e)
{
var client = (TClientBase)sender;
client.Error -= OnClientBaseError;
OnClientDisconnected(client, e.Exception);
client.DetachClient(e.Exception);
Clients.TryRemove(client.Id, out _);
}
// utility method to write data to all clients connected
public void WriteDataToAllClients(byte[] data)
{
Parallel.ForEach(Clients, x => x.Value.WriteData(data));
}
}
}
At this point all the basics of running a server have been accounted for. Now for the client that runs on the server:
namespace MultiServerExample.Base
{
public interface IAsyncClientBase
{
event EventHandler<AsyncClientBaseErrorEventArgs> Error;
void AttachClient(TcpClient client);
void WriteData(byte[] data);
void DetachClient(Exception ex);
string Id { get; }
}
public abstract class AsyncClientBase : IAsyncClientBase
{
protected virtual int ReceiveBufferSize { get; } = 1024;
private TcpClient Client { get; set; }
private byte[] ReceiveBuffer { get; set; }
public event EventHandler<AsyncClientBaseErrorEventArgs> Error;
public string Id { get; }
public AsyncClientBase()
{
Id = Guid.NewGuid().ToString();
}
public void AttachClient(TcpClient client)
{
if(ReceiveBuffer != null) { throw new InvalidOperationException(); }
ReceiveBuffer = new byte[ReceiveBufferSize];
Client = client;
try
{
Client.GetStream().
BeginRead(ReceiveBuffer, 0, ReceiveBufferSize, OnDataReceived, this);
OnAttachedToServer();
}
catch (Exception ex)
{
Error?.Invoke(this,
new AsyncClientBaseErrorEventArgs(ex, "BeginRead"));
}
}
public void DetachClient(Exception ex)
{
try
{
Client.Close();
OnDetachedFromServer(ex);
}
catch { /* intentionally swallow */ }
Client = null;
ReceiveBuffer = null;
}
public virtual void OnDataReceived(byte[] buffer) { }
public virtual void OnAttachedToServer() { }
public virtual void OnDetachedFromServer(Exception ex) { }
public void WriteData(byte[] data)
{
try
{
Client.GetStream().BeginWrite(data, 0, data.Length, OnDataWrote, this);
}
catch(Exception ex)
{
Error?.Invoke(this, new AsyncClientBaseErrorEventArgs(ex, "BeginWrite"));
}
}
private static void OnDataReceived(IAsyncResult iar)
{
var me = (AsyncClientBase)iar.AsyncState;
if(me.Client == null) { return; }
try
{
var bytesRead = me.Client.GetStream().EndRead(iar);
var buf = new byte[bytesRead];
Array.Copy(me.ReceiveBuffer, buf, bytesRead);
me.OnDataReceived(buf);
}
catch (Exception ex)
{
me.Error?.Invoke(me, new AsyncClientBaseErrorEventArgs(ex, "EndRead"));
}
}
private static void OnDataWrote(IAsyncResult iar)
{
var me = (AsyncClientBase)iar.AsyncState;
try
{
me.Client.GetStream().EndWrite(iar);
}
catch(Exception ex)
{
me.Error?.Invoke(me,
new AsyncClientBaseErrorEventArgs(ex, "EndWrite"));
}
}
}
}
Now all your base code is written. You don't need to change this in any way. You simply implement your own client and server to respond accordingly. For example, here is a basic server implementation:
public class MyServer : AsyncServerBase<MyClient>
{
public MyServer(int port) : base(port)
{
}
public override void OnClientConnected(MyClient client)
{
Console.WriteLine($"* MyClient connected with Id: {client.Id}");
base.OnClientConnected(client);
}
public override void OnClientDisconnected(MyClient client, Exception ex)
{
Console.WriteLine($"***** MyClient disconnected with Id: {client.Id} ({ex.Message})");
base.OnClientDisconnected(client, ex);
}
}
And here is a client that the server above uses for communication:
public class MyClient : AsyncClientBase
{
public override void OnAttachedToServer()
{
base.OnAttachedToServer();
Console.WriteLine($"{Id}: {GetType().Name} attached. Waiting for data...");
}
public override void OnDataReceived(byte[] buffer)
{
base.OnDataReceived(buffer);
Console.WriteLine($"{Id}: {GetType().Name} recieved {buffer.Length} bytes. Writing 5 bytes back.");
WriteData(new byte[] { 1, 2, 3, 4, 5 });
}
public override void OnDetachedFromServer(Exception ex)
{
base.OnDetachedFromServer(ex);
Console.WriteLine($"{Id}: {GetType().Name} detached.");
}
}
And to drive the point home, here is another client that simply would plug in to the same server implementation, but gives it different characteristics:
public class MyOtherClient : AsyncClientBase
{
public override void OnAttachedToServer()
{
base.OnAttachedToServer();
Console.WriteLine($"{Id}: {GetType().Name} attached. Writing 4 bytes back.");
WriteData(new byte[] { 1, 2, 3, 4 });
}
public override void OnDataReceived(byte[] buffer)
{
base.OnDataReceived(buffer);
Console.WriteLine($"{Id}: {GetType().Name} recieved {buffer.Length} bytes.");
}
public override void OnDetachedFromServer(Exception ex)
{
base.OnDetachedFromServer(ex);
Console.WriteLine($"{Id}: {GetType().Name} detached.");
}
}
As far as using this, here is a small test program that puts it through a stress-test:
class Program
{
static void Main(string[] args)
{
var servers = new IAsyncServerBase[]
{
new MyServer(50000),
new MyServer(50001),
new MyOtherServer(50002)
};
foreach (var s in servers)
{
s.StartListening();
}
RunTestUsingMyServer("1", 89, 50000);
RunTestUsingMyServer("2", 127, 50001);
RunTestUsingMyOtherServer("3", 88, 50002);
Console.Write("Press any key to exit... ");
Console.ReadKey(true);
foreach (var s in servers)
{
s.WriteDataToAllClients(new byte[] { 1, 2, 3, 4, 5 });
s.StopListening();
}
}
private static void RunTestUsingMyServer(string name, int clientCount, int port)
{
Parallel.For(0, clientCount, x =>
{
using (var t = new TcpClient())
{
t.Connect(IPAddress.Loopback, port);
t.GetStream().Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
t.GetStream().Read(new byte[512], 0, 512);
t.Close();
}
Console.WriteLine($"FINISHED PASS {name} #{x}");
});
}
private static void RunTestUsingMyOtherServer(string name, int clientCount, int port)
{
Parallel.For(0, clientCount, x =>
{
using (var t = new TcpClient())
{
t.Connect(IPAddress.Loopback, port);
t.GetStream().Read(new byte[512], 0, 512);
t.GetStream().Write(new byte[] { 1, 2, 3, 4, 5, 6 }, 0, 6);
t.Close();
}
Console.WriteLine($"FINISHED PASS {name} #{x}");
});
}
}
If interested, here is the full source code you can check out. Hopefully this gets you to where you want to be as it pertains to reusing code.
I don't know if this can help. You can define a state object with all the information related to every port:
public class StateObject
{
public string Name;
public Socket Listener;
public IPEndPoint LocalEndPoint;
//...
public StateObject(Socket listener, IPEndPoint endPoint, string name)
{
Listener = listener;
LocalEndPoint = endPoint;
Name = name;
}
}
Then, you can use it as you need:
public static void StartListeningMaster()
{
string ipAddress = "localhost";
IPHostEntry ipHost = Dns.GetHostEntry(ipAddress);
IPAddress address = ipHost.AddressList[0];
StartListening(50000, address, "Main port");
StartListening(50001, address, "Service port");
StartListening(50002, address, "Extra");
//...
}
public static void StartListening(int port, IPAddress ipAddress, string name = "")
{
//...
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
//...
StateObject state = new StateObject(listener, localEndPoint);
listener.BeginAccept(AcceptCallback, state);
//...
}
public static void AcceptCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
//...
handler.BeginReceive(client.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
// Always have the info related to every socket
Socket listener = state.Listener;
string address = state.LocalEndPoint.Address.ToString();
int port = state.LocalEndPoint.Port;
string name = state.Name;
//...
StateObject state = (StateObject)ar.AsyncState;
//...
CalculateResult(state);
//...
handler.BeginReceive(client.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
//...
}
The CalculateResult(state) method will have all the necessary info to do whatever. This way, you only have one StartListening(), one AcceptCallback() and one ReadCallback() for all the ports to manage.
i'm trying to do a new application for android. I connected my C# app with Android app by sockets and i can send texts easily. However, the point i couldn't do is sending pictures. Client Android app will send a text and my desktop app will answer with a bitmap image. I tried Base64 coding but it's not working for me. I'm stuck.
C# server response code;
else if(text.ToLower() == "resim")
{
response = "resim gönderiliyor...";
byte[] text_ = Encoding.UTF8.GetBytes(response);
socket.BeginSend(text_, 0, text_.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
Thread.Sleep(3000);
byte[] buffer = ToBase64String(ScreenCaptured(), ImageFormat.Bmp);
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
ToBase64String function;
public string ToBase64String(Bitmap bmp, ImageFormat imageFormat)
{
string base64String = string.Empty;
MemoryStream memoryStream = new MemoryStream();
bmp.Save(memoryStream, imageFormat);
memoryStream.Position = 0;
byte[] byteBuffer = memoryStream.ToArray();
memoryStream.Close();
base64String = Convert.ToBase64String(byteBuffer);
byteBuffer = null;
return base64String;
}
Android Client Side;
public void addListener(OnListener listener) {
this.listener = listener;
}
static Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (flag) {
bmp = SixtyFourBaseToBitmap(msg.obj.toString());
if(bmp != null)
{
imgView.setImageBitmap(bmp);
}
else
{
kq += msg.obj.toString() + "\r\n";
textResponse.setText(kq);
}
}
}
};
public static Bitmap SixtyFourBaseToBitmap(String codedString)
{
try
{
byte[] decodedString = Base64.decode(codedString, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
return decodedByte;
}
catch (Exception e)
{
return null;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonConnect = (ImageButton) findViewById(R.id.connect_button);
settings_button_ = (ImageButton) findViewById(R.id.settings_button);
textResponse = (TextView) findViewById(R.id.response);
imgView = (ImageView) findViewById(R.id.response_img);
preferences= PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
editor = preferences.edit();
ipbilgisi=preferences.getString("ip", "IP Girin");
portBilgisi= preferences.getString("port", "Port Girin");
buttonConnect.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
myClientTask = new ClientTask(ipbilgisi, portBilgisi);
myClientTask.execute();
}
});
}
public void goSettings(View v)
{
Intent i = new Intent(this, Settings.class);
startActivity(i);
finish();
}
public class ClientTask extends AsyncTask<String, String, String> implements
OnListener {
String dstAddress;
int dstPort;
PrintWriter out1;
ClientTask(String addr, String port) {
dstAddress = addr;
dstPort = Integer.parseInt(port);
}
#Override
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
try {
socket = new Socket(dstAddress, dstPort);
out1 = new PrintWriter(socket.getOutputStream(), true);
//out1.print("Hello server!");
out1.flush();
BufferedReader in1 = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
do {
try {
if (!in1.ready()) {
if (message != null) {
MainActivity.handler.obtainMessage(0, 0, -1,
"Server: " + message).sendToTarget();
message = "";
}
}
int num = in1.read();
message += Character.toString((char) num);
} catch (Exception classNot) {
}
} while (!message.equals("bye"));
try {
sendMessage("bye");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
try {
if (socket.isClosed()) {
flag = false;
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Bağlantı Hatası!", Toast.LENGTH_LONG).show();
}
super.onPostExecute(result);
}
#Override
public void listener(String text) {
// TODO Auto-generated method stub
sendMessage(text);
}
void sendMessage(String msg) {
try {
out1.print(msg);
out1.flush();
if (!msg.equals("bye"))
MainActivity.handler.obtainMessage(0, 0, -1, "Me: " + msg)
.sendToTarget();
else
MainActivity.handler.obtainMessage(0, 0, -1,
"Ngắt kết nối!").sendToTarget();
} catch (Exception ioException) {
ioException.printStackTrace();
}
}
}
public void send(View v) {
addListener(myClientTask);
if (listener != null)
listener.listener(((EditText) findViewById(R.id.editText1))
.getText().toString());
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
try {
if (listener != null)
listener.listener("bye");
socket.close();
} catch (Exception e) {
// TODO: handle exception
}
super.onDestroy();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
try {
if (listener != null)
listener.listener("bye");
socket.close();
} catch (Exception e) {
// TODO: handle exception
}
super.onStop();
}
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
}
Your help is appreciated.
Best regards.
I've made an application that obeys UDP using Datagram Socket in android. I'm trying to use Camera's setPreviewCallback function to send bytes to a (c#) client, using Datagram Socket;
But,
The problem is : it throws an exception "The datagram was too big to fit the specified buffer,so truncated" and no bytes are received on client.
I've changed the size of buffer to different values but none work. Now :
Is Datagram approach is right?
What alternatives/approach I'd use to achieve the task?
What's the ideal solution for this?
Android Server :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView = (VideoView) findViewById(R.id.videoView1);
start = (Button)findViewById(R.id.start);
stop = (Button)findViewById(R.id.stop);
setTitle(GetCurrentIP());
mainList = new LinkedList<byte[]>();
secondaryList = new LinkedList<byte[]>();
mCam = null;
mCam = Camera.open();
if (mCam == null) {
Msg("Camera is null");
} else {
if (!Bind()) {
Msg("Bind Error.");
} else {
Msg("Bound Success.");
start.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
mCam.setPreviewDisplay(videoView.getHolder());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
Msg(e1.getMessage());
}
mCam.setPreviewCallback(new PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
DatagramPacket pack;
try {
pack = new DatagramPacket(data, data.length, InetAddress.getByName(clientIP), clientPort);
me.send(pack);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Msg(e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Msg(e.getMessage());
}
}
});
mCam.startPreview();
}
});
}
}
}
private boolean Bind(){
try {
me = new DatagramSocket(MY_PORT);
return true;
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Msg(e.getMessage());
}
return false;
}
private String GetCurrentIP(){
WifiManager wifiMgr = (WifiManager) getSystemService(WIFI_SERVICE);
return Formatter.formatIpAddress(wifiMgr.getConnectionInfo().getIpAddress());
}
public void Msg(String msg){
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
Log.v(">>>>>", msg);
}
}
C# client :
public partial class Form1 : Form
{
const int MY_PORT = 55566;
IPAddress MY_IP;
Thread Receiver;
Socket me;
EndPoint myEndPoint;
EndPoint serverEndPoint;
byte[] buffer;
public Form1()
{
InitializeComponent();
}
private IPAddress GetCurrentIPAddress()
{
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
var selectedIPs = from ip in ips
where ip.AddressFamily == AddressFamily.InterNetwork
select ip;
return selectedIPs.First();
}
private bool Bind()
{
try
{
myEndPoint = new IPEndPoint(MY_IP, MY_PORT);
me.Bind(myEndPoint);
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return false;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
MY_IP = GetCurrentIPAddress();
this.Text = MY_IP.ToString()+":"+MY_PORT;
me = new Socket
(
AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp
);
if (!Bind())
Task.Run(()=> MessageBox.Show("Bind() error."));
else
Task.Run(() => MessageBox.Show("Bind success."));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//private void AddToListBox(String msg)
//{
// this.Invoke((Action)delegate() { this.listBox1.Items.Add((this.listBox1.Items.Count+1)+" : "+msg); });
//}
private void buttonStart_Click(object sender, EventArgs e)
{
serverEndPoint = new IPEndPoint(IPAddress.Parse(textBoxmyIP.Text), int.Parse(textBoxmyPort.Text));
Receiver = new Thread(new ThreadStart(Receive));
Receiver.Start();
}
private Image ByteToImage(byte[] bytes)
{
MemoryStream ms = new MemoryStream(bytes);
return Image.FromStream(ms);
}
private void Receive()
{
while (true)
{
buffer = new byte[100];
int nobs = me.ReceiveFrom(buffer, ref serverEndPoint);
if (nobs>0)
{
Task.Run(() => MessageBox.Show("Bytes received"));
//AddToListBox(Encoding.Default.GetString(buffer));
//AddToPictureBox(buffer);
}
Thread.Sleep(100);
}
}
private void AddToPictureBox(byte[] buffer)
{
this.BeginInvoke
(
(Action)
delegate()
{
pictureBox1.Image = ByteToImage(buffer);
}
);
}
}
I keep getting this error:
"The IAsyncResult object was not returned from the corresponding asynchonous method on this class. Parameter name : aysncResult. Line 105.
This happens when I attempt to connect to a local server; It errors and won't connect.
Here's my client code:
public class Client
{
public delegate void OnConnectEventHandler(Client sender, bool connected);
public event OnConnectEventHandler OnConnect;
public delegate void OnSendEventHandler(Client sender, int sent);
public event OnSendEventHandler OnSend;
public delegate void OnDisconnectEventHandler(Client sender);
public event OnDisconnectEventHandler OnDisconnect;
Socket socket;
public bool Connected
{
get
{
if (socket != null)
{
return socket.Connected;
}
return false;
}
}
public Client()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void SendData()
{
}
public void Connect(string IP, int port)
{
if (socket == null)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
socket.BeginConnect(IP, port, new AsyncCallback(sendCallback), null);
}
private void connectCallback(IAsyncResult ar)
{
//try
//{
socket.EndConnect(ar);
if (OnConnect != null)
{
OnConnect(this, Connected);
}
//}
//catch
//{
//}
}
public void Send(byte[] data, int index, int length)
{
socket.BeginSend(BitConverter.GetBytes(length), 0, 4, SocketFlags.None, new AsyncCallback(sendCallback), null);
socket.BeginSend(data, index, length, SocketFlags.None, new AsyncCallback(sendCallback), null);
}
private void sendCallback(IAsyncResult ar)
{
try
{
int sent = socket.EndSend(ar); ( errrors here )
if (OnSend != null)
{
OnSend(this, sent);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
return;
}
}
public void Disconnect()
{
try
{
if (socket.Connected)
{
socket.Close();
socket = null;
if (OnDisconnect != null)
{
OnDisconnect(this);
}
}
}
catch
{
}
}
you should not have two pending BeginSend operations.
Send the size and then the buffer when it completes:
public void Send(byte[] data, int index, int length)
{
//add data as state
socket.BeginSend(BitConverter.GetBytes(length), 0, 4, SocketFlags.None, sendCallback, data);
}
private void sendCallback(IAsyncResult ar)
{
try
{
int sent = socket.EndSend(ar); ( errrors here )
// check if data was attached.
if (ar.AsyncState != null)
{
byte[] buffer = (byte[])ar.AsyncState;
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
return;
}
if (OnSend != null)
{
OnSend(this, sent);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
return;
}
}
You can also use the BeginSend overload which takes a list of buffers.