I'm having trouble getting my Sender thread to connect to my Receiver thread. Here's my code below (I'm a novice when it comes to socket programming so if you know a better of sending images over sockets please let me know):
Sender thread:
public void SendSS()
{
try
{
while (!mainFrm.ssStop)
{
TcpClient ssTcpClient = new TcpClient();
ssTcpClient.Connect(mainFrm.contactIP, 1500);
if (ssTcpClient.Connected)
{
Image screenShotBMP = GrabScreen();
NetworkStream ns = ssTcpClient.GetStream();
memStream = new MemoryStream();
screenShotBMP.Save(memStream, ImageFormat.Png);
byte[] bytesToSend = memStream.ToArray(); ;
ns.Write(bytesToSend, 0, bytesToSend.Length);
ns.Flush();
screenShotBMP.Dispose();
ns.Close();
memStream.Close();
ssTcpClient.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "frmVoiceChat-SendSS()", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Receiver thread:
public void ReceiveSS()
{
try
{
TcpListener ssTcpListener = new TcpListener(IPAddress.Any, 1500);
while (!mainFrm.ssStop)
{
ssTcpListener.Start();
TcpClient tcpReceiver = ssTcpListener.AcceptTcpClient();
//TcpClient tcpReceiver = new TcpClient();
ssTcpListener.AcceptTcpClient();
//tcpReceiver.Connect(mainFrm.contactIP, 1500);
if (tcpReceiver.Connected)
{
labelText("Connected!!!");
//NetworkStream receivedNs = tcpReceiver.GetStream();
NetworkStream receivedNs = new NetworkStream(tcpReceiver.Client);
//ssTcpListener.Server.Receive();
//byte[] imageBytes = new byte[tcpReceiver.ReceiveBufferSize];
//receivedNs.Read(imageBytes, 0, imageBytes.Length);
//MemoryStream receivedMs = new MemoryStream(imageBytes);
//receivedNs.CopyTo(receivedMs);
//Image image = Image.FromStream(receivedNs); // ArgumentException: Parameter is not valid exception here.
pbScreenShare.Image = new Bitmap(receivedNs);
receivedNs.Close();
tcpReceiver.Close();
ssTcpListener.Stop();
//image.Dispose();
//receivedMs.Close();
}
else
{
labelText("Not Connected!!!");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "frmVoiceChat-ReceiveSS()", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
You call AcceptTcpClient() twice. The second call will wait for a connection and block the rest of the code from executing. Please clean up your code.
Related
I´ve got a problem with my TCP client.
My TCP server sends a Bitmap as a String to the TCP client. At the moment there are 15 bmp per second. My Problem is, that most of them are read as "//////...." when I convert the received byte array to a string.
My TCP server code is (C#):
private void StreamWriter(byte[] writeMessage)
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Parse(Ip), Port);
NetworkStream streamSender = client.GetStream();
streamSender.Write(writeMessage, 0, writeMessage.Length);
streamSender.Flush();
streamSender.Close();
client.Close();
}
private void sendImage()
{
while (send)
{
MemoryStream mem = new MemoryStream();
image.Save(mem, System.Drawing.Imaging.ImageFormat.Bmp);
mem.Close();
mem.Dispose();
StreamWriter(Encoding.ASCII.GetBytes(Convert.ToBase64String(mem.ToArray())));
i++;
}
}
My client code is (Android Studio):
class MyServerThread implements Runnable {
#Override
public void run() {
try {
ServerSocket ss = new ServerSocket(50000);
while (true) {
Socket s = ss.accept();
InputStream is = (s.getInputStream());
BufferedInputStream bufferedReader = new BufferedInputStream(is);
byte[] contents = new byte[440000];
int bytesRead = 0;
while ((bytesRead = bufferedReader.read(contents)) != -1) {
message = new String(contents, 0, bytesRead);
}
is.close();
bufferedReader.close();
if (message.equals("Connection OK!")) {
createIP();
} else {
createPic();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I found a solution.
This is the client code now:
class MyServerThread implements Runnable {
#Override
public void run() {
try {
ServerSocket ss = new ServerSocket(50000);
while (true) {
Socket s = ss.accept();
InputStream is = (s.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(is));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
message = total.toString();
s.close();
is.close();
if (message.equals("Connection OK!")) {
createIP();
} else {
createPic();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I want my server to keep listening the the same client. It listen the client only one time. How can i keep reading the data sent from client side.
sk = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
sk.Bind(new IPEndPoint(IPAddress.Any, 5000));
sk.Listen(-1);
while (true)
{
try
{
Socket client = sk.Accept();
NetworkStream ns = new NetworkStream(client);
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = ns.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
ms.Write(buffer, 0, read);
}
}
MemoryStream msi = new MemoryStream(buffer);
Image returnImage = Image.FromStream(msi);
}
catch (Exception)
{
}
}
Finally i found a way to this problem
private void Form1_Load(object sender, EventArgs e)
{
serverSocket = new TcpListener(9361);
clientSocket = default(TcpClient);
Thread listen = new Thread(listenClients);
listen.Start();
}
//this will keep listening the clients
public void listenClients()
{
int counter = 0;
serverSocket.Start();
counter = 0;
while ((true))
{
counter += 1;
clientSocket = serverSocket.AcceptTcpClient();
Thread thread = new Thread(
() => readClient(clientSocket));
thread.Start();
}
}
public void broadcast(Image bmp)
{
pictureBox1.Image = bmp;
} //en
//keep reading the client data
private void readClient(TcpClient inClientSocket)
{
byte[] bytesFrom = new byte[65536];
string dataFromClient = null;
while ((true))
{
try
{
NetworkStream networkStream = inClientSocket.GetStream();
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
MemoryStream ms = new MemoryStream(bytesFrom);
Image returnImage = Image.FromStream(ms);
broadcast(returnImage);
}
catch (Exception ex)
{
}
} //end while
} //end readClint
My Server Class:
namespace Net_Send_File
{
class Server
{
private TcpListener listener;
private IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 15550);
private bool active;
string arg;
// private Socket xxx;
public Server()
{
Console.Clear();
Console.Title = "Server";
Main();
}
private void Main()
{
listener = new TcpListener(ipep);
try
{
listener.Start();
active = true;
ListenForConnections();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
private void ListenForConnections()
{
Console.Clear();
Console.WriteLine("Listening for connections...");
while (active)
{
TcpClient client = listener.AcceptTcpClient();
Console.BackgroundColor = ConsoleColor.Green;
Console.WriteLine("Connection # {0}", TCPIP(client));
new Thread(new ParameterizedThreadStart(HandleClientData)).Start(client);
}
}
private void HandleClientData(object _c)
{
TcpClient c = (TcpClient)_c;
string ipaddr = TCPIP(c);
NetworkStream s = c.GetStream();
// I tried this byte[] buffer = new byte[c.ReceiveBufferSize]; It throws an Exeption.
byte[] buffer = new byte[1024];
int bytesRead;
while (active)
{
bytesRead = 0;
try
{
bytesRead = s.Read(buffer, 0, buffer.Length/2);
}
catch (Exception ex)
{
Console.WriteLine("Socket error # {0}:\r\n{1}", ipaddr, ex.Message);
Console.ReadLine();
break;
}
if (bytesRead == 0)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("Disconnected # {0}", ipaddr);
//new Thread(new ParameterizedThreadStart.ListenForConnections);
break;
}
string dataStr = Encoding.ASCII.GetString(buffer, 0, buffer.Length);
using (var fs = File.OpenWrite("test.txt"))
{
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
}
}
private string TCPIP(TcpClient c)
{
return ((IPEndPoint)c.Client.RemoteEndPoint).Address.ToString();
}
};
My Client Class:
class Client
{
private TcpClient client;
// private TcpClient client1;
private IPEndPoint ipep;
private int port;
public Client()
{
Console.Clear();
Console.Title = "Client";
bool error = false;
while (true)
{
Console.WriteLine("IPEndPoint: ");
string input = Console.ReadLine();
if (!input.Contains(':'))
{
Console.WriteLine("IPEndPoint in bad format");
break;
}
string[] s1 = input.Split(':');
IPAddress ipaddr;
if (!IPAddress.TryParse(s1[0], out ipaddr) || !int.TryParse(s1[1], out port))
{
Console.WriteLine("IPEndPoint in bad format");
Console.ReadLine();
error = true;
break;
}
ipep = new IPEndPoint(ipaddr, port);
try
{
client = new TcpClient();
client.Connect(ipep);
Console.WriteLine("client 1 is Ready!");
//client1 = new TcpClient();
//client1.Connect(ipep);
//Console.WriteLine("client 2 is Ready!");
}
catch (Exception ex)
{
Console.WriteLine("Unable to connect\r\nReason: {0}", ex.Message);
Console.ReadLine();
error = true;
}
break;
}
while (!error)
{
Console.Clear();
Console.WriteLine("File path: ");
string filePath = Console.ReadLine();
if (File.Exists(filePath) == false)
{
Console.WriteLine("File does not exist\r\nPress ENTER to try again");
Console.ReadLine();
}
byte[] buffer;
using (var fs = File.OpenRead(filePath))
{
buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
Int64 a = client.SendBufferSize; ;
fs.Close();
}
if (SendData(buffer))
{
// client.SendBufferSize(buffer);
//int a = client.SendBufferSize; ;
Console.WriteLine("File sent\r\nFile size: {0} KB", (buffer.Length / 1024));
//a.SetLength((buffer.Length / 1024));
Console.ReadLine();
}
break;
}
}
private bool SendData(byte[] data)
{
try
{
using (NetworkStream ns = client.GetStream())
{
ns.Write(data, 0, data.Length);
ns.Close();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("Unable to send file\r\nReason: {0}\r\nDetailed:\r\n{1}", ex.Message, ex.ToString());
Console.ReadLine();
return false;
}
}
}
}
}
First of all accept my apologise for my code is badly commented. Or to be honest no comments at all, almost.
Server class, under the method called private void HandleClient Data(object _) I have a buffer. Buffer is set to byte[1024]. I want to receive bufferSize (of my test file) from client, set Server buffer = to ClientBuffer and there after receive file. I have a test file which is 60MB. I tried to send my buffer size from client to server but it doesn't work well. Can someone tell me what I can do and how?
thanks in advance
You should implement an application level protocol, for example:
MESSAGE:
[SIZE (8 BYTES)][DATA (SIZE BYTES)]
Then, use BinaryReader and BinaryWriter
//client
var writer = new BinaryWriter(client.GetStream());
FileInfo fileInfoToSend = new FileInfo(path);
long fileSize = fileInfoToSend.Length;
writer.Write(fileSize);
using (FileStream fileStream = fileInfoToSend .Open(FileMode.Open, FileAccess.Read))
{
fileStream.CopyTo(writer.BaseStream);
fileStream.Close();
}
//server
var stream = c.GetStream();
var reader = new BinaryReader(c.GetStream());
FileInfo fileInfoToWrite = new FileInfo(path);
long fileSize = reader.ReadInt64();
using (FileStream fileStream = fileInfoToWrite.Create())
{
int read = 0;
for (long i = 0; i < fileSize; i += (long)read)
{
byte[] buffer = new byte[1024];
read = stream.Read(buffer, 0, Math.Min(fileSize - i, 1024));
if (read == 0)
return;//client disconnected!(or throw Exception)
fileStream.Write(buffer, 0, read);
}
}
untested
I'm currently receiving text:
private void ReceiveCallback(IAsyncResult AR)
{
try
{
int received = _clientSocket.EndReceive(AR);
//string text = Encoding.ASCII.GetString(_buffer);
Array.Resize(ref _buffer, received);
//AppendToTextBox(text);
Array.Resize(ref _buffer, _clientSocket.ReceiveBufferSize);
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
How can I read an image, instead of text?
You'd probably want to wait to receive the entire thing, and then:
using(var ms = new MemoryStream(entireBuffer)) {
var image = Image.FromStream(ms);
// Go ahead and put it in a PictureBox now
}
I'm attempting to create a remote desktop server and client using C#. The server captures the screen and then sends it to the client via a socket. I'm using the code below although it only displays a part of the jpeg image on the client. I think this is because the image is sent in multiple packets and at the moment the code only reads the one packet and displays it. Can anyone explain how I would change my code so it receives multiple packets (the whole image) before displaying it.
Server code:
Socket serverSocket;
Socket clientSocket;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8221);
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(4);
//Accept the incoming clients
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Stream Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
Rectangle bounds = new Rectangle(0, 0, 1280, 720);
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
System.IO.MemoryStream stream = new System.IO.MemoryStream();
ImageCodecInfo myImageCodecInfo;
System.Drawing.Imaging.Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
myEncoderParameters = new EncoderParameters(1);
myImageCodecInfo = GetEncoderInfo("image/jpeg");
myEncoder = System.Drawing.Imaging.Encoder.Quality;
myEncoderParameter = new EncoderParameter(myEncoder, 40L);
myEncoderParameters.Param[0] = myEncoderParameter;
bitmap.Save(stream, myImageCodecInfo, myEncoderParameters);
byte[] imageBytes = stream.ToArray();
stream.Dispose();
clientSocket.Send(imageBytes);
timer1.Start();
}
As you can see, I'm using a timer which has the interval set to 30 for sending the image bytes.
Client code:
public Socket clientSocket;
byte[] byteData = new byte[2048];
MemoryStream ms;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
this.DoubleBuffered = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("MY EXTERNAL IP HERE"), 8221);
//Connect to the server
clientSocket.BeginConnect(ipEndPoint,
new AsyncCallback(OnConnect), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "SGSclient",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void OnConnect(IAsyncResult ar)
{
try
{
//Start listening to the data asynchronously
clientSocket.BeginReceive(byteData,
0,
byteData.Length,
SocketFlags.None,
new AsyncCallback(OnReceive),
null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Stream Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OnReceive(IAsyncResult ar)
{
try
{
int byteCount = clientSocket.EndReceive(ar);
ms = new MemoryStream(byteData);
using (BinaryReader br = new BinaryReader(ms))
{
this.BackgroundImage = Image.FromStream(ms).GetThumbnailImage(this.ClientRectangle.Width, this.ClientRectangle.Height, null, IntPtr.Zero);
}
}
catch (ArgumentException e)
{
//MessageBox.Show(e.Message);
}
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
}
The client is meant to receive the image and then display it on the form's background.
You need to add application level protocol to your socket communications.
Add a header to all messages sent. The header contains the count of bytes that follow. It is simpler code and performs better to have a byte count than to kludge a termination sequence.
The client then does two sets of reads:
1) Read for the number of bytes that are known to be in any header.
2) After extracting the byte count from the header, loop reading until you get the indicated byte count.
A must-read article for all people who are writing socket communications: http://nitoprograms.blogspot.com/2009/04/message-framing.html
From that article: Repeat this mantra three times: "TCP does not operate on packets of data. TCP operates on streams of data."
I have previously answered a similar question, and provided a fully working example that I think does exactly what you are trying to do. See: transferring a screenshot over a TCP connection
You must set a delimiter at the end of your image, some set of bytes that will sinalize the server that the image has ended. It's also known as end of file (EOF) or end of message. TCP won't split the image into logical packets for your app, so you must write your own control of information.
The logic would be similar to this:
CLIENT
byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ImageBytes = GetImageBytes();
byte[] BytesToSend = new byte[EndOfMessage.Length + ImageBytes.Length];
Array.Copy(ImageBytes, 0, BytesToSend);
Array.Copy(EndOfMessage, 0, BytesToSend, ImageBytes.Length, EndOfMessage.Length);
SendToServer(BytesToSend);
SERVER
byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ReceivedBytes;
while(!IsEndOfMessage(ReceivedBytes, EndOfMessage ))
{
//continue reading from socket and adding to ReceivedBytes
}
ReceivedBytes = RemoveEndOfMessage(ReceivedBytes, EndOfMessage );
PrintImage(ReceivedBytes);
I'm at work right now and I can't provide a full running example, I'm sorry.
Regards
Support methods:
private bool IsEndOfMessage(byte[] MessageToCheck, byte[] EndOfMessage)
{
for(int i = 0; i++; i < EndOfMessage.Length)
{
if(MessageToCheck[MessageToCheck.Length - (EndOfMessage.Length + i)] != EndOfMessage[i])
return false;
}
return true;
}
private byte[] RemoveEndOfMessage(byte[] MessageToClear, byte[] EndOfMessage)
{
byte[] Return = new byte[MessageToClear.Length - EndOfMessage.Length];
Array.Copy(MessageToClear, Return, Return.Length);
return Return;
}
Again, I couldn't test them, so you may find some bugs.