C# socket just first message received - c#

I have searched many examples and tutorials and what not but I cant for the life of me figure out what im doing wrong here... If I send several messages to this server I made only the first is printed in the Console.Writeline command and the rest is never printed... I must be doing something fundametally wrong but I really cant find it ... :S
This is the server code:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms.VisualStyles;
namespace HL7_Manager
{
public class MonitorServer
{
private int _port;
private Socket _serverSocket;
private List<ClientObject> _clients;
public bool IsConnected { get; set; }
public MonitorServer(int port)
{
_port = port;
_clients = new List<ClientObject>();
}
public void StartListening()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Thread listenThread = new Thread(new ThreadStart(ListenerThread));
listenThread.IsBackground = true;
listenThread.Start();
}
public void StopListening()
{
IsConnected = true;
_serverSocket.Close();
while (_clients.Count > 0)
{
_clients[0].KeepProcessing = false;
_clients[0].ClientSocket.Close();
_clients.RemoveAt(0);
}
}
private void ListenerThread()
{
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, _port));
_serverSocket.Listen(100);
Console.WriteLine("Listening on port 8000");
while (true)
{
Socket clientSocket = _serverSocket.Accept();
ClientObject client = new ClientObject();
client.KeepProcessing = true;
client.ClientSocket = clientSocket;
_clients.Add(client);
ParameterizedThreadStart ptStart = new ParameterizedThreadStart(ProcessClientThread);
Thread processThread = new Thread(ptStart);
processThread.IsBackground = true;
processThread.Start(client);
clientSocket = null;
client = null;
}
}
private void ProcessClientThread(object clientObj)
{
Console.WriteLine("Client connected");
ClientObject client = (ClientObject) clientObj;
Socket clientSocket = client.ClientSocket;
byte[] buffer = new byte[clientSocket.ReceiveBufferSize];
int receiveCount = 0;
while (client.KeepProcessing)
{
try
{
receiveCount = clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
Console.WriteLine(Encoding.ASCII.GetString(buffer));
}
catch (Exception ex)
{
if (!client.KeepProcessing)
return;
Console.WriteLine(ex.Message);
}
}
clientSocket.Close();
_clients.Remove(client);
}
}
}

Here is the method you should definitely change and how to change it.
private void ProcessClientThread(object clientObj)
{
Console.WriteLine("Client connected");
ClientObject client = (ClientObject)clientObj;
Socket clientSocket = client.ClientSocket;
byte[] buffer = new byte[clientSocket.ReceiveBufferSize];
int receiveCount = 0;
while (client.KeepProcessing)
{
try
{
receiveCount = clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
if (receiveCount == 0)
break; //the client has closed the stream
var ret = Encoding.ASCII.GetString(buffer, 0, receiveCount);
Console.WriteLine(ret);
}
catch (Exception ex)
{
if (!client.KeepProcessing)
return;
Console.WriteLine(ex.Message);
}
}
clientSocket.Close();
_clients.Remove(client);
}

Check how many bytes you really received.
TCP is a streaming protocol this means that if you client is doing several sends of small messages right one after the other, you will receive them in one go at the receiver.
If there happens to be a null character in your receive buffer you might think you did not receive all those string, but actually you did.
Check this by inspecting how many bytes you received and by checking the buffer content.
If you made this mistake there might be some deeper problem in your code. The fact that TCP is streaming makes it a bit more complex

Related

C# socket datagram overflow

I'm new in c# =)
I have a litle question about udp socket.
I have a chat server that receives packets to a specific structure (udp datagram).
Why program receives data when the socket buffer is full? Does all that come after should not be be lost? Maybe packet fragmentation occurs?
Packet structure : udp_headers(28 byte)| dataIdentifier ( 4 byte)|name length(4 byte)|mesage length (4 bytes)|name(name length)|message(message length)
When I send a packet larger than the internal buffer. The program throws an exception:
ReceiveData Error: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself
All I need is to drop such packets before they cause this error. Is it possible?
Server code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Collections;
using ChatApplication;
namespace ChatServer
{
public partial class Server : Form
{
#region Private Members
// Structure to store the client information
private struct Client
{
public EndPoint endPoint;
public string name;
}
// Listing of clients
private ArrayList clientList;
// Server socket
private Socket serverSocket;
// Data stream
private byte[] dataStream = new byte[1024];
// Status delegate
private delegate void UpdateStatusDelegate(string status);
private UpdateStatusDelegate updateStatusDelegate = null;
#endregion
#region Constructor
public Server()
{
InitializeComponent();
}
#endregion
#region Events
private void Server_Load(object sender, EventArgs e)
{
try
{
// Initialise the ArrayList of connected clients
this.clientList = new ArrayList();
// Initialise the delegate which updates the status
this.updateStatusDelegate = new UpdateStatusDelegate(this.UpdateStatus);
// Initialise the socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Initialise the IPEndPoint for the server and listen on port 30000
IPEndPoint server = new IPEndPoint(IPAddress.Any, 30000);
// Associate the socket with this IP address and port
serverSocket.Bind(server);
// Initialise the IPEndPoint for the clients
IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);
// Initialise the EndPoint for the clients
EndPoint epSender = (EndPoint)clients;
// Start listening for incoming data
serverSocket.BeginReceiveFrom(this.dataStream, 0, 1024, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveData), epSender);
lblStatus.Text = "Listening";
}
catch (Exception ex)
{
lblStatus.Text = "Error";
MessageBox.Show("Load Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnExit_Click(object sender, EventArgs e)
{
Close();
}
#endregion
#region Send And Receive
public void SendData(IAsyncResult asyncResult)
{
try
{
serverSocket.EndSend(asyncResult);
}
catch (Exception ex)
{
MessageBox.Show("SendData Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ReceiveData(IAsyncResult asyncResult)
{
try
{
byte[] data;
// Initialise a packet object to store the received data
Packet receivedData = new Packet(this.dataStream);
// Initialise a packet object to store the data to be sent
Packet sendData = new Packet();
// Initialise the IPEndPoint for the clients
IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);
// Initialise the EndPoint for the clients
EndPoint epSender = (EndPoint)clients;
// Receive all data
serverSocket.EndReceiveFrom(asyncResult, ref epSender);
// Start populating the packet to be sent
sendData.ChatDataIdentifier = receivedData.ChatDataIdentifier;
sendData.ChatName = receivedData.ChatName;
switch (receivedData.ChatDataIdentifier)
{
case DataIdentifier.Message:
sendData.ChatMessage = string.Format("{0}: {1}", receivedData.ChatName, receivedData.ChatMessage);
break;
case DataIdentifier.LogIn:
// Populate client object
Client client = new Client();
client.endPoint = epSender;
client.name = receivedData.ChatName;
// Add client to list
this.clientList.Add(client);
sendData.ChatMessage = string.Format("-- {0} is online --", receivedData.ChatName);
break;
case DataIdentifier.LogOut:
// Remove current client from list
foreach (Client c in this.clientList)
{
if (c.endPoint.Equals(epSender))
{
this.clientList.Remove(c);
break;
}
}
sendData.ChatMessage = string.Format("-- {0} has gone offline --", receivedData.ChatName);
break;
}
// Get packet as byte array
data = sendData.GetDataStream();
foreach (Client client in this.clientList)
{
if (client.endPoint != epSender || sendData.ChatDataIdentifier != DataIdentifier.LogIn)
{
// Broadcast to all logged on users
serverSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, client.endPoint, new AsyncCallback(this.SendData), client.endPoint);
}
}
// Listen for more connections again...
serverSocket.BeginReceiveFrom(this.dataStream, 0, 1024, SocketFlags.None, ref epSender, new AsyncCallback(this.ReceiveData), epSender);
// Update status through a delegate
this.Invoke(this.updateStatusDelegate, new object[] { sendData.ChatMessage });
}
catch (Exception ex)
{
MessageBox.Show("ReceiveData Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Other Methods
private void UpdateStatus(string status)
{
rtxtStatus.Text += status + Environment.NewLine;
}
#endregion
}
}
This is udp sender and reciver in one . Use /s if you want listen
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace UDPTestClient
{
class Program
{
static void RecvCompleted(object sender, SocketAsyncEventArgs e)
{
string Data = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred);
e.Dispose();
ReceiveUdp((Socket)e.UserToken);
Console.WriteLine(Data);
}
static void SendCompleted(object sender, SocketAsyncEventArgs e)
{
int i = e.Count;
e.Dispose();
Console.WriteLine("{0} bytes send", i);
}
static void ReceiveUdp(Socket s)
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
//set buffer to 100 .Now it's work fine.
e.SetBuffer(new byte[100], 0, 100);
e.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(RecvCompleted);
s.ReceiveFromAsync(e);
}
static void SendUdp(Socket s, string Data)
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
byte[] buf = Encoding.ASCII.GetBytes(Data);
e.SetBuffer(buf, 0, buf.Length);
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3333);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCompleted);
s.SendToAsync(e);
}
static void Main(string[] args)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
if (args.Length != 0 && args[0] == "/s")
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 3333);
s.Bind(ip);
ReceiveUdp(s);
}
else
{
SendUdp(s, "Hello!");
}
Console.ReadKey();
s.Close();
}
}
}
UDP is a dumb protocol, as in, it does not actually have any knowledge of size or how to work with this. If you want to handle this before an exception occurs, you need to create a different structure for your communication. I would recommend that you do one of the following:
Use a polling mechanism, where the client requests a single update from the server, with a given size, then ensure that the buffer is large enough for this message.
Simply increase your buffer to the correct size.
Catch the exception and simply discard it, when the buffer overflows, then attempt to reestablish.
Use RecieveAsync to only get parts of the datagram at a time. See
http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.110).aspx

Socket Programming - A connection attempt failed Exception

Am new to socket programming and am creating a chat application.As like other applications whenever i press enter in a chat window it should send the chat to a particular user.Am maintaining a DB for all users along with their IPAddresses.So whenever i select a user for sending chat it should send to the corresponding IPAddress.As of now am trying to send chat to my own machine(so i hard coded the IPAddress of my machine).But am getting an exception when i try to send my code to my IPAddress.Can anyone please help me out.
My code for socket programming is this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.Net.Sockets;
namespace Ping
{
class SocketProgramming
{
//Socket m_socWorker;
public AsyncCallback pfnWorkerCallBack;
public Socket m_socListener;
public Socket m_socWorker;
public void sendChat(IPAddress toMessengerIP)
{
try
{
//create a new client socket ...
m_socWorker = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
String szIPSelected = toMessengerIP.ToString();
String szPort = "7777";
int alPort = System.Convert.ToInt16(szPort, 10);
System.Net.IPAddress remoteIPAddress = System.Net.IPAddress.Parse(szIPSelected);
System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(remoteIPAddress, alPort);
// receive();
m_socWorker.Connect(remoteEndPoint);
//Send data
Object objData =(object)"hi dhivi";
byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
m_socWorker.Send(byData);
}
catch (System.Net.Sockets.SocketException se)
{
//MessageBox.Show(se.Message);
Console.Out.Write(se.Message);
}
}
public void receive()
{
try
{
//create the listening socket...
m_socListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 7777);
//bind to local IP Address...
m_socListener.Bind(ipLocal);
//start listening...
m_socListener.Listen(4);
// create the call back for any client connections...
m_socListener.BeginAccept(new AsyncCallback(OnClientConnect), null);
//cmdListen.Enabled = false;
}
catch (SocketException se)
{
Console.Out.Write(se.Message);
}
}
public void OnClientConnect(IAsyncResult asyn)
{
try
{
m_socWorker = m_socListener.EndAccept(asyn);
WaitForData(m_socWorker);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
}
catch (SocketException se)
{
Console.Out.Write(se.Message);
}
}
public class CSocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[1];
}
public void WaitForData(System.Net.Sockets.Socket soc)
{
try
{
//if (pfnWorkerCallBack == null)
//{
// pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
//}
CSocketPacket theSocPkt = new CSocketPacket();
theSocPkt.thisSocket = soc;
// now start to listen for any data...
soc.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt);
}
catch (SocketException se)
{
Console.Out.Write(se.Message);
}
}
}
}
And whenever the users clicks the enter button it should call the sendChat() method.
private void txt_Userinput_KeyDown_1(object sender, KeyEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
TabItem tb = (TabItem)this.Parent;
string user = tb.Header.ToString();
if (e.Key == Key.Return)
{
richtxtbox_chatwindow.AppendText(Environment.NewLine + user + " : " + txt_Userinput.Text);
DBCoding dbObject = new DBCoding();
SocketProgramming socketObj = new SocketProgramming();
socketObj.sendChat(IPAddress.Parse("192.168.15.41"));
}
else { return; }
}
To get ipaddress of the user
public IPAddress getIP()
{
String direction = "";
WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
using (WebResponse response = request.GetResponse())
using (StreamReader stream = new StreamReader(response.GetResponseStream()))
{
direction = stream.ReadToEnd();
}
//Search for the ip in the html
int first = direction.IndexOf("Address: ") + 9;
int last = direction.LastIndexOf("</body>");
direction = direction.Substring(first, last - first);
IPAddress ip = IPAddress.Parse(direction);
return ip;
}
You never seem to be calling your receive method. If your application never starts listening, no one will ever be able to connect. If you've tried that, and is getting an exception, post that and we'll go from there.

Send text file directly to network printer

I have currently-working code which sends raw data to a printer by writing a temporary file, then using File.Copy() to send it to the printer. File.Copy() supports both local ports, like LPT1 and shared printers like \\FRONTCOUNTER\LabelPrinter.
However, now I'm trying to get it working with a printer that's directly on the network: 192.168.2.100, and I can't figure out the format to use.
File.Copy(filename, #"LPT1", true); // Works, on the FRONTCOUNTER computer
File.Copy(filename, #"\\FRONTCOUNTER\LabelPrinter", true); // Works from any computer
File.Copy(filename, #"\\192.168.2.100", true); // New printer, Does not work
I know it's possible to "Add a printer" from each computer, but I'm hoping to avoid that - the second line of code above works from any computer on the network automatically, with no configuration required. I also know it's possible to P/Invoke the windows print spooler, and if that's my only option I may take it, but that's much more code overhead than I'd like to have.
Ideally, someone will have either a way to make File.Copy() work or a similar C# statement which will accept a network IP.
You can use sockets and send the data straight to that IP address. Should pretty much be the same as File.Copy. I just tried it out and that worked.
I just sent some text but here is the code that I used
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.NoDelay = true;
IPAddress ip = IPAddress.Parse("192.168.192.6");
IPEndPoint ipep = new IPEndPoint(ip, 9100);
clientSocket.Connect(ipep);
byte[] fileBytes = File.ReadAllBytes("test.txt");
clientSocket.Send(fileBytes);
clientSocket.Close();
try this code:
public class PrintHelper
{
private readonly IPAddress PrinterIPAddress;
private readonly byte[] FileData;
private readonly int PortNumber;
private ManualResetEvent connectDoneEvent { get; set; }
private ManualResetEvent sendDoneEvent { get; set; }
public PrintHelper(byte[] fileData, string printerIPAddress, int portNumber = 9100)
{
FileData = fileData;
PortNumber = portNumber;
if (!IPAddress.TryParse(printerIPAddress, out PrinterIPAddress))
throw new Exception("Wrong IP Address!");
}
public PrintHelper(byte[] fileData, IPAddress printerIPAddress, int portNumber = 9100)
{
FileData = fileData;
PortNumber = portNumber;
PrinterIPAddress = printerIPAddress;
}
/// <inheritDoc />
public bool PrintData()
{
//this line is Optional for checking before send data
if (!NetworkHelper.CheckIPAddressAndPortNumber(PrinterIPAddress, PortNumber))
return false;
IPEndPoint remoteEP = new IPEndPoint(PrinterIPAddress, PortNumber);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.NoDelay = true;
connectDoneEvent = new ManualResetEvent(false);
sendDoneEvent = new ManualResetEvent(false);
try
{
client.BeginConnect(remoteEP, new AsyncCallback(connectCallback), client);
connectDoneEvent.WaitOne();
client.BeginSend(FileData, 0, FileData.Length, 0, new AsyncCallback(sendCallback), client);
sendDoneEvent.WaitOne();
return true;
}
catch
{
return false;
}
finally
{
// Shutdown the client
this.shutDownClient(client);
}
}
private void connectCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
connectDoneEvent.Set();
}
private void sendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
// Signal that all bytes have been sent.
sendDoneEvent.Set();
}
private void shutDownClient(Socket client)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
Network Helper class:
public static class NetworkHelper
{
public static bool CheckIPAddressAndPortNumber(IPAddress ipAddress, int portNumber)
{
return PingIPAddress(ipAddress) && CheckPortNumber(ipAddress, portNumber);
}
public static bool PingIPAddress(IPAddress iPAddress)
{
var ping = new Ping();
PingReply pingReply = ping.Send(iPAddress);
if (pingReply.Status == IPStatus.Success)
{
//Server is alive
return true;
}
else
return false;
}
public static bool CheckPortNumber(IPAddress iPAddress, int portNumber)
{
var retVal = false;
try
{
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.Connect(iPAddress, portNumber);
retVal = tcpClient.Connected;
tcpClient.Close();
}
return retVal;
}
catch (Exception)
{
return retVal;
}
}
}

Problem with simple tcp\ip client-server

i'm trying to write simple tcp\ip client-server.
here is server code:
internal class Program
{
private const int _localPort = 7777;
private static void Main(string[] args)
{
TcpListener Listener;
Socket ClientSock;
string data;
byte[] cldata = new byte[1024];
Listener = new TcpListener(_localPort);
Listener.Start();
Console.WriteLine("Waiting connections [" + Convert.ToString(_localPort) + "]...");
try
{
ClientSock = Listener.AcceptSocket();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
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();
ClientSock.Send(cldata);
}
}
catch
{
ClientSock.Close();
Listener.Stop();
Console.WriteLine(
"Server closing. Reason: client offline. Type EXIT to quit the application.");
}
}
}
}
}
And here is client code:
void Main()
{
string data; // Юзерская дата
byte[] remdata ={ };
TcpClient Client = new TcpClient();
string ip = "127.0.0.1";
int port = 7777;
Console.WriteLine("\r\nConnecting to server...");
try
{
Client.Connect(ip, port);
}
catch
{
Console.WriteLine("Cannot connect to remote host!");
return;
}
Console.Write("done\r\nTo end, type 'END'");
Socket Sock = Client.Client;
while (true)
{
Console.Write("\r\n>");
data = Console.ReadLine();
if (data == "END")
break;
Sock.Send(Encoding.ASCII.GetBytes(data));
Sock.Receive(remdata);
Console.Write("\r\n<" + Encoding.ASCII.GetString(remdata));
}
Sock.Close();
Client.Close();
}
When i'm sending to my server i cannt receive data back answer. Sock.Receive(remdata) returns nothing! Why?
You're trying to receive to an empty buffer. You should allocate the buffer with a sensible size, and then take note of the amount of data received:
byte[] buffer = new byte[1024];
...
int bytesReceived = socket.Receive(buffer);
string text = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
(It's somewhat unconventional to use PascalCase for local variables, by the way. I'd also urge you not to just catch Exception blindly, and not to swallow exceptions without logging them.)

How to make a Fully Async proxy (http 1.0 compiant not 1.1)

For a school project I am making a multi-client proxy that has to be compliant with http 1.0 and not 1.1(so that makes it easier). The teacher told me that it is better to make it fully async. So I made a fully async proxy, there is only one problem. It only works when I put a threadsleep in it, but this is not making it faster, but it's the only way to let it work. Please help me find a solution and maybe someone knows why it needs the threadsleep to let it work?
The teacher sees this problem every year and the only found solution is the threadsleep, so the teacher has not found a real solution.
First the simple code for the form. The form has a start button and a textbox to view the request and a textbox to view the responds. After the form follows the code for the proxy.
By the way, in internet explorer you can switch to a http 1.0 mode, so that's the best way to test, also you need to make the browser listen to a proxyserver(listed in de code).
using System;
using System.Windows.Forms;
using System.Threading;
namespace Proxy
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void startProxy_Click(object sender, EventArgs e)
{
var proxy = new Proxy(requestView, respondsView);
var thread = new Thread(new ThreadStart(proxy.StartProxy));
thread.IsBackground = true;
thread.Start();
startProxy.Enabled = false;
}
}
}
And now the proxy where the problem exists...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace Proxy
{
class Proxy
{
private TextBox requestView;
private TextBox respondsView;
private delegate void UpdateLogCallback(string strMessage, TextBox txtView);
public const int PROXY_PORT = 5008;
public const int WEB_PROXY_PORT = 80;
public const int BACKLOG = 20;
public const int TIMEOUT = 4000;
public Proxy(TextBox _requestView, TextBox _respondsView)
{
requestView = _requestView;
respondsView = _respondsView;
}
public void StartProxy()
{
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
clientSocket.Bind(new IPEndPoint(IPAddress.Any, PROXY_PORT));
clientSocket.Listen(BACKLOG);
clientSocket.BeginAccept(HandleConnection, clientSocket);
}
private void HandleConnection(IAsyncResult iar)
{
Socket clientSocket = iar.AsyncState as Socket;
Socket client = clientSocket.EndAccept(iar);
clientSocket.BeginAccept(HandleConnection, clientSocket);
SocketData data = new SocketData() { SocketToClient = client };
client.BeginReceive(data.buffer, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnDataArrived, data);
}
private void OnDataArrived(IAsyncResult iar)
{
SocketData socketdata = iar.AsyncState as SocketData;
int bytesreceived = 0;
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
socketdata.SocketToClient.ReceiveTimeout = TIMEOUT;
try
{
bytesreceived = socketdata.SocketToClient.EndReceive(iar);
if (bytesreceived == SocketData.BUFFER_SIZE)
{
socketdata.sb.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer, 0, bytesreceived));
socketdata.SocketToClient.BeginReceive(socketdata.buffer, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnDataArrived, socketdata);
}
else
{
socketdata.sb.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer, 0, bytesreceived));
string strContent = socketdata.sb.ToString();
string[] testing = strContent.Split(' ');
if (testing[0] == "CONNECT")
{
//this is to prevent weird request to microsoft servers(???) also prevents ssl request...
}
else
{
IPEndPoint ip = new IPEndPoint(Dns.GetHostEntry(GetHostnameFromRequest(strContent)).AddressList[0], WEB_PROXY_PORT);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
server.Connect(ip);
requestView.Invoke(new UpdateLogCallback(uLC), new object[] { strContent, requestView });
server.Send(System.Text.ASCIIEncoding.ASCII.GetBytes(strContent));
socketdata.SocketToServer = server;
server.BeginReceive(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnWebsiteDataArrived, socketdata);
}
}
}
catch
{
socketdata.SocketToClient.Close();
}
}
private void OnWebsiteDataArrived(IAsyncResult iar)
{
SocketData socketdata = iar.AsyncState as SocketData;
int bytesreceived = 0;
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
socketdata.SocketToServer.ReceiveTimeout = TIMEOUT;
try
{
bytesreceived = socketdata.SocketToServer.EndReceive(iar);
Thread.Sleep(10);
if (bytesreceived == SocketData.BUFFER_SIZE)
{
socketdata.sb2.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer2, 0, bytesreceived));
socketdata.SocketToClient.Send(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None);
socketdata.SocketToServer.BeginReceive(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnWebsiteDataArrived, socketdata);
}
else
{
socketdata.sb2.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer2, 0, bytesreceived));
respondsView.Invoke(new UpdateLogCallback(uLC), new object[] { socketdata.sb2.ToString(), respondsView });
socketdata.SocketToClient.Send(socketdata.buffer2, 0, bytesreceived, SocketFlags.None);
socketdata.SocketToClient.Close();
socketdata.SocketToServer.Close();
}
}
catch
{
socketdata.SocketToClient.Close();
}
}
private static string GetHostnameFromRequest(string strContent)
{
string[] host = strContent.Split(new string[] { "\r\n", ": " }, StringSplitOptions.RemoveEmptyEntries);
int check = Array.IndexOf(host, "Host");
return host[check + 1];
}
public void ReceiveMessages(string receiveMessages, TextBox txtView)
{
if (txtView.InvokeRequired)
{
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
txtView.Invoke(new UpdateLogCallback(uLC), new object[] { receiveMessages, txtView });
}
else
{
txtView.AppendText(receiveMessages);
}
}
public class SocketData
{
public SocketData()
{
this.packetlenght = 0;
}
public Socket SocketToClient { get; set; }
public Socket SocketToServer { get; set; }
public StringBuilder sb = new StringBuilder();
public StringBuilder sb2 = new StringBuilder();
public const int BUFFER_SIZE = 128;
public byte[] buffer = new byte[BUFFER_SIZE];
public byte[] buffer2 = new byte[BUFFER_SIZE];
public int packetlenght { get; set; }
}
}
}
From Socket.EndReceive:
The EndReceive method will block until data is available. If you are using a connectionless protocol, EndReceive will read the first enqueued datagram available in the incoming network buffer. If you are using a connection-oriented protocol, the EndReceive method will read as much data as is available up to the number of bytes you specified in the size parameter of the BeginReceive method.
I read that to imply that (if you're on a slow network), it may return a size < SocketData.BUFFER_SIZE at any time, not just when you've received the end of the message. So the delay probably adds enough time that the only time it returns < SocketData.BUFFER_SIZE is once the message is complete.
You should go through your naming since it makes it hard to follow your code.
As an example: clientSocket is not a very good name for a listening socket.
Your exception handling is not good. At least log the exceptions.
And you need to check if the number of received bytes is zero. It indicates that the remote socket has closed the connection.
Your proxy thread will die directly since BeginAccept is not a blocking operation.
I do not understand your if in OnDataArrived. Why the check to see if the number of bytes is the same as the buffer size? TCP do not guarantee anything when it comes to received data. A partially filled buffer do not mean that the message is complete. Continue to build the buffer until the number of body bytes is the same as the specified Content-Length.
The same goes for OnWebsiteDataArrived. You are trying to use TCP in a way that it's not intended for. It's not message oriented. Keep building the buffer as suggested in #5.

Categories