C# socket hangs when receive in loop - python as socket server - c#

I'm familiar with C#, and know some python. Recent days I'm learning the book Programming Python, 4th Edition and have run the very basic socket samples: echo-server.py and echo-client.py
They work well on my Windows, python 3.x.
python server:
from socket import *
myHost = 'localhost'
myPort = 50007
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.bind((myHost, myPort))
sockobj.listen(5)
while True:
connection, address = sockobj.accept()
print('Server connected by', address)
while True:
data = connection.recv(1024)
if not data: break
connection.send(b'Echo=>' + data)
connection.close()
Now I want to learn socket in C# too, so I wrote a C# .net framework 4.5 socket client, expecting to receive and show what echo-client.py does.
I got the C# demo from msdn and made some refactor to reduce code size.
public static void Main(string[] args)
{
string server = "localhost";
int port = 50007;
string request = "GET / HTTP/1.1\r\nHost: " + server +
"\r\nConnection: Close\r\n\r\n";
Byte[] sent = Encoding.ASCII.GetBytes(request);
Byte[] recv = new Byte[256];
IPHostEntry hostEntry = Dns.GetHostEntry(server);
IPEndPoint ipe = new IPEndPoint(hostEntry.AddressList[1], port);
Socket s =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Connect(ipe);
s.Send(sent, sent.Length, 0);
int bytes = 0;
string page = "recived:\r\n";
//do
{
bytes = s.Receive(recv, recv.Length, 0);
page = page + Encoding.ASCII.GetString(recv, 0, bytes);
}
//while (bytes > 0);
Console.WriteLine(page);
Console.WriteLine("result");
Console.ReadKey();
}
My test steps:
If I set up a web site using local IIS, such as
http://localhost:801, then above code can show the homepage html
contents, this means my C# code is working.
Run echo-server.py, and change C# code's port to 50007, then run,
nothing output in console, and application does not exit, if I place a break point within the loop, I can see the loop has only run once. The python server did output some log saying C# is connecting.
Comment do while loop(as commented in code), this time the output is exactly same as echo-client.py(expected).
So I'm wondering what's wrong when I'm using do while loop?

Related

TCP socket communication for image streaming and Texture2D error

I want to ask for some ideas about why this error occurs.
First, let me show you the symptom of my project <- .gif file is uploaded in this link.
I implemented this project with Python TCP server and Unity client.
As you watch this .gif file, Unity displays the streaming depth image from the Python server.
Although Unity seems to show the image stream in real-time, it also shows 'query mark' frequently.
I heard that this query mark is displayed whenever unity Texture2D is failed to receive data, but even I added a flag to check loading image is true or false, it always true.
Furthermore, When you see the console of Unity, it also shows there are some lost-bytes comparing to the python console (black console is for the python).
I already tested this TCP server works well with python client(that code is also uploaded above link). So, I assumed it is Unity's problem, but I don't know in detail and want to know how to fix this.
This is my Python TCP server:
mport pyrealsense2 as d435
import socketserver
import socket
import cv2
import numpy as np
from queue import Queue
from _thread import *
# _Set queue
enclosure_queue = Queue()
# _Configures of depth and color streams
pipeline = d435.pipeline()
config = d435.config()
config.enable_stream(d435.stream.depth, 640, 480, d435.format.z16, 30)
config.enable_stream(d435.stream.color, 640, 480, d435.format.bgr8, 30)
# _ D435 process
def D435(queue):
print("D435 processing", end="\n ")
pipeline.start(config) # _Start streaming
try:
while True:
# _Wait for a coherent pair of frames: depth and color
frames = pipeline.wait_for_frames()
depth_frame, color_frame = (frames.get_depth_frame(), frames.get_color_frame())
if not (depth_frame and color_frame):
print("Missing frame...", end="\n")
continue
# _Convert <pyrealsense2 frame> to <ndarray>
depth_image = np.asanyarray(depth_frame.get_data()) # convert any array to <ndarray>
color_image = np.asanyarray(color_frame.get_data())
# _Apply colormap on depth image
# (image must be converted to 8-bit per pixel first)
depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.05), cv2.COLORMAP_BONE)
#depth_colormap = cv2.bitwise_not(depth_colormap ) # reverse image
#print("Depth map shape = ", depth_colormap.shape)
# _Encoding
target_frame = depth_colormap
#print(target_frame.shape)
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY),95] # 0 ~ 100 quality
#encode_param = [cv2.IMWRITE_PNG_COMPRESSION,0] # 0 ~ 9 Compressiong rate
#encode_param = [int(cv2.IMWRITE_WEBP_QUALITY),95] # 0 ~ 100 quality
result, imgencode = cv2.imencode('.jpg', target_frame, encode_param) # Encode numpy into '.jpg'
data = np.array(imgencode)
stringData = data.tostring() # Convert numpy to string
print("byte Length: ", len(stringData))
queue.put(stringData) # Put the encode in the queue stack
# __ Image show
images = np.hstack((color_image, depth_colormap)) # stack both images horizontally
cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
cv2.imshow('RealSense', images)
cv2.waitKey(1)
finally:
cv2.destroyAllWindows()
# _Stop streaming
pipeline.stop()
class MyTCPHandler(socketserver.BaseRequestHandler):
queue = enclosure_queue
stringData = str()
def handle(self):
# 'self.request' is the TCP socket connected to the client
print("A client connected by: ", self.client_address[0], ":", self.client_address[1] )
while True:
try:
# _server <- client
self.data = self.request.recv(1024).strip() # 1024 byte for header
if not self.data:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
# _Get data from Queue stack
MyTCPHandler.stringData = MyTCPHandler.queue.get()
# _server -> client
#print(str(len(MyTCPHandler.stringData)).ljust(16).encode()) # <str>.ljust(16) and encode <str> to <bytearray>
self.request.sendall(str(len(MyTCPHandler.stringData)).ljust(16).encode())
self.request.sendall(MyTCPHandler.stringData)
#self.request.sendall(len(MyTCPHandler.stringData).to_bytes(1024, byteorder= "big"))
#self.request.sendall(MyTCPHandler.stringData)
except ConnectionResetError as e:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
if __name__ == "__main__":
# _Webcam process is loaded onto subthread
start_new_thread(D435, (enclosure_queue,))
# _Server on
HOST, PORT = socket.gethostname(), 8080
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
print("****** Server started ****** ", end="\n \n")
try:
server.serve_forever()
except KeyboardInterrupt as e:
print("****** Server closed ****** ", end="\n \n" )
and Unity script:
Client_unity.cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace imageStream_client
{
public class Client_unity : MonoBehaviour
{
IPHostEntry ipHostInfo;
IPAddress ipAddress; // IPv4
TcpClient client_sock;
const int PORT = 8080;
NetworkStream stream;
// Start is called before the first frame update
void Start()
{
Debug.Log("*****Unity frame started *****");
ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
ipAddress = ipHostInfo.AddressList[1];
client_sock = new TcpClient(ipAddress.ToString(), PORT);
Debug.Log("***** Client Connected to the server *****");
stream = client_sock.GetStream();
}
// Update is called once per frame
void Update()
{
//Debug.Log("**** Buffer streaming ****");
// _Client -> Server
string message = "1";
byte[] buff = Encoding.ASCII.GetBytes(message);
stream.Write(buff, 0, buff.Length); // spend the byte stream into the Stream
// _Client <- Server
byte[] recvBuf = new byte[client_sock.ReceiveBufferSize]; // total receiveBuffer size
int readBytes = stream.Read(recvBuf, 0, recvBuf.Length);
//Debug.Log($"total receiveBuffer length: {recvBuf.Length}");
Debug.Log($"Real-read byte length: {readBytes}");
// _Set display image
byte[] image = new byte[readBytes];
Buffer.BlockCopy(recvBuf, 0, image, 0, readBytes);
Viewer.instance.SetImageToDisplay(image);
//Viewer.instance.SetImageToDisplay();
}
}
}
Viewer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace imageStream_client
{
public class Viewer : MonoBehaviour
{
public RawImage rawimage;
public AspectRatioFitter fit;
#region Data
public static Viewer instance;
private byte[] imageToDisplay;
#endregion
#region Get Set
public void SetImageToDisplay(byte[] image)
{
DisplayImage(image);
//instance.imageToDisplay = image;
}
#endregion
#region API
internal static void DisplayImage(byte[] image)
{
if (image == null)
return;
if (image.Length > 0)
{
//이미지 크기 생성 이후 streaming 되는 이미지 크기에 맞게 수정 해야함
Texture2D texture = new Texture2D(640, 480);
//byte형식의 데이터를 texture2D 형식으로 읽음
bool load = texture.LoadImage(image);
if (load)
{
//이미지를 화면에 입힘(Canvas 아래 RawImage)
instance.rawimage.texture = texture as Texture;
//이미지 가로 세로 비율
instance.fit.aspectRatio = 640 / 480;
}
}
}
#endregion
// Start is called before the first frame update
void Awake()
{
instance = this;
}
// Update is called once per frame
void Update()
{
//DisplayImage(instance.imageToDisplay);
}
}
}
The problem is that you moved your read function into update, which calles every frame in Unity, so you just cant catch to receive data.
The solution is:
void Start()
{
Debug.Log("*****Unity frame started *****");
ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
ipAddress = ipHostInfo.AddressList[1];
client_sock = new TcpClient(ipAddress.ToString(), PORT);
Debug.Log("***** Client Connected to the server *****");
stream = client_sock.GetStream();
StartReceiveFunction();
}
void StartReceiveFunction()
{
// Can be Application.IsRunning or whatever bool you need to receive data
while (true)
{
if(stream.CanRead && client_sock.ReceiveBufferSize > 0){
bytes = new byte[client_sock.ReceiveBufferSize];
stream.Read(bytes, 0, client_sock.ReceiveBufferSize);
Viewer.instance.SetImageToDisplay(image);
}
}
Okay, I found the problem and fixed it.
The problem was the wrong implementation of the TCP server.
I changed the python server code like below:
class MyTCPHandler(socketserver.BaseRequestHandler):
queue = enclosure_queue
stringData = str()
def handle(self):
# 'self.request' is the TCP socket connected to the client
print("A client connected by: ", self.client_address[0], ":", self.client_address[1] )
while True:
try:
# _server <- client
self.data = self.request.recv(1024).strip() # 1024 byte for header
#print("Received from client: ", self.data)
if not self.data:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
# _Get data from Queue stack
MyTCPHandler.stringData = MyTCPHandler.queue.get()
# _server -> client
#print(str(len(MyTCPHandler.stringData)).ljust(16).encode()) # <str>.ljust(16) and encode <str> to <bytearray>
###self.request.sendall(str(len(MyTCPHandler.stringData)).ljust(16).encode()) # <- Make this line ignored when you connect with C# client.
self.request.sendall(MyTCPHandler.stringData)
#self.request.sendall(len(MyTCPHandler.stringData).to_bytes(1024, byteorder= "big"))
#self.request.sendall(MyTCPHandler.stringData)
except ConnectionResetError as e:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
I had tested this server code with a python TCP client.
When the client connected to the server and spending-receiving data, it should know the size of the buffer to transmitted data by the server.
So, self.request.sendall(str(len(MyTCPHandler.stringData)).ljust(16).encode()) is needed.
However, TCPclient class in C# is sort of different to python one. it doesn't need to receive the explicit buffer size of transmitted data from the server (maybe that was processed automatically inside). So, the above-mentioned python code line can be ignored.
I reuploaded the new version here.

Named Pipes IPC: Python server, C# Client

Title sums it up. There are plenty of examples around with a c# server and python client communicating back and forth.
I'd like to understand how I can instead create a python server and c# client for some interprocess communication.
I managed to find a solution. To begin, I'd first like to clarify some confusing terminology and obscure naming conventions used in dotnet core.
It appears that the NamedPipeServerStream and NamedPipeClientStream don't actually operate on named pipes but instead on unix domain sockets. This means that we must use sockets to communicate between processes rather than FIFO files.
Another frustration I find with dotnet core is that when creating a socket or connecting to one, the NamedPipeServerStream and NamedPipeClientStream classes will add "CoreFxPipe_" to the beginning of the socket name. See related question.
Python Server
#!/usr/bin/python3
import socket
import os
import struct
SOCK_PATH = "/tmp/CoreFxPipe_mySocket"
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
try:
os.remove(SOCK_PATH)
except OSError:
pass
sock.bind(SOCK_PATH)
sock.listen()
conn, addr = sock.accept()
with conn:
try:
while True:
amount_expected = struct.unpack('I', conn.recv(4))[0]
print("amount_expected :", amount_expected)
message = conn.recv(amount_expected)
print("Received message : ", message.decode())
# Send data
message_rev = message[::-1].decode()
print("Sent message (reversed) : ", message_rev)
conn.sendall(
struct.pack(
'I',
len(message_rev)
)
+ message_rev.encode('utf-8')
)
except (struct.error, KeyboardInterrupt) as e:
print(e)
finally:
print('closing socket')
C# Client
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
class PipeClient
{
static void Main(string[] args)
{
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream(".", "mySocket", PipeDirection.InOut))
{
// Connect to the pipe or wait until the pipe is available.
Console.WriteLine("Attempting to connect to pipe...");
pipeClient.Connect();
try
{
// Read user input and send that to the client process.
using (BinaryWriter _bw = new BinaryWriter(pipeClient))
using (BinaryReader _br = new BinaryReader(pipeClient))
{
while (true)
{
//sw.AutoFlush = true;
Console.Write("Enter text: ");
var str = Console.ReadLine();
var buf = Encoding.ASCII.GetBytes(str); // Get ASCII byte array
_bw.Write((uint)buf.Length); // Write string length
_bw.Write(buf); // Write string
Console.WriteLine("Wrote: \"{0}\"", str);
Console.WriteLine("Let's hear from the server now..");
var len = _br.ReadUInt32();
var temp = new string(_br.ReadChars((int)len));
Console.WriteLine("Received from client: {0}", temp);
}
}
}
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
}
Console.Write("Press Enter to continue...");
}
}
Sources:
https://abgoswam.wordpress.com/2017/07/13/named-pipes-c-python-net-core/
https://realpython.com/python-sockets/
https://unix.stackexchange.com/questions/75904/are-fifo-pipe-unix-domain-socket-the-same-thing-in-linux-kernel

UWP nativemessaging host print to network printer using sockets in C#

We are trying to build an UWP app with native messaging where the user will print labels on their network printers. Here is the code
string printerIPAddress = msg.ipAddress;
int printerPort = msg.port;
IPAddress addr = IPAddress.Parse(printerIPAddress);
IPEndPoint remoteEP = new IPEndPoint(addr, printerPort);
Socket clientSock =
new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
byte[] zplBytes = Encoding.ASCII.GetBytes((string)msg.zplText);
clientSock.Connect(remoteEP);
var bytesSent = clientSock.Send(zplBytes, zplBytes.Length, 0);
I am getting the following error:
Exception thrown:
'System.Net.Internals.SocketExceptionFactory.ExtendedSocketException'
in System.Net.Sockets.dll
System.Net.Internals.SocketExceptionFactory+ExtendedSocketException:
An attempt was made to access a socket in a way forbidden by its access permissions
We have built similar native messaging app for chrome and FF and we can print using network printer without any issue.

Connect an C# application thats running sockets using JAVASCRIPT

Hey i was wondering if you could help me
I'm creating an android application in html5 and java script.
There are a server that is created on c# that is listing connection.
I can connect the 2 apps together but get i can get the c# app to reply to my android application using javascript.
here is my server code
public void Listeners()
{
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
nr_connections = nr_connections + 1;
nr_qry = nr_qry + 1;
SetText("");
SetText("New Connection.");
NetworkStream networkStream = new NetworkStream(socketForClient);
StreamWriter streamWriter = new StreamWriter(networkStream);
StreamReader streamReader = new StreamReader(networkStream);
streamWriter.Flush();
string GettheString = streamReader.ReadLine();
if (GettheString == "server_status")
{
SetText("Checking Server Status.");
streamWriter.WriteLine("Online");
streamWriter.Close();
streamReader.Close();
networkStream.Close();
}
}
socketForClient.Close();
SetText("Connection Closed...");
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
nr_connections = nr_connections - 1;
}
and my javascript code
function connect ()
{
try
{
var connection = new WebSocket('ws://105.237.125.247:8');
connection.onopen = function ()
{
connection.send('server_status');
};
connection.onmessage = function (event) {
alert(event.data);
}
}
catch(Exeption)
{
alert("Check Connection");
}
}
Im getting data from the android app but can send back to the javascript file
Web-sockets is a protocol that sits on top of a regular transport (such as a socket); basically, you need a web-socket library. If you are using recent versions of Windows, then much of this is baked into HTTP.SYS, and available via HttpListnener (in particular, AcceptWebSocketAsync on a context). However, alternative web-socket libraries are available, or can be written from scratch if you so choose.

Raw FTP SSL with C#

I'm trying to understand how SSL works. In my wish to make a small FTP client which supports SSL I've run into some problems:
TcpClient FtpConnection = new TcpClient(FtpServer, FtpPort);
NetworkStream FtpStream = FtpConnection.GetStream();
StreamReader FtpReader = new StreamReader(FtpStream);
FtpWriter = new StreamWriter(IrcStream);
send_cmd("AUTH SSL");
send_cmd is just a FtpWriter.WriteLine(text); FtpWriter.Flush(); function.
My "problem" is this: First I need to make a (non-ssl) connection to the FTP, then tell it to do a ssl connection (AUTH SSL), and I would guess I then need to make a new connection - something like:
TcpClient client = new TcpClient(FtpServer, FtpPort);
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
sslStream.AuthenticateAsClient("foobar");
}
catch (AuthenticationException e)
{
MessageBox.Show("Authentication failed - closing the connection.");
client.Close();
return;
}
Taken from msdn.
I keep dying on handshake failed due to unexpected packet format (which I've tried googling, but all say it's because the author has connected to a wrong port), which I take as: The connection is not ssl until AUTH SSL is send to it. So my question is, how would i go about making this a "hybrid" connection so I can make an SSL connection to the server?
Any help is greatly appreciated!
Using a library like that is the opposite of what I wanted. Since I found so few hits when searching the web, I'll post what I figured out:
Building a C# ftp client is basically like so:
TcpClient blabla = new TcpClient("some.host", 21);
NetworkStream blabla_stream = blabla.GetStream();
StreamReader unsecure_reader = new StreamReader(blabla_stream);
StreamWriter blabla_writer = new StreamWriter(blabla_stream);
blabla_writer.WriteLine("AUTH SSL");
string response = "";
while ((response = unsecure_reader.ReadLine()) != null)
{
if (response.Substring(0,3) == "234")
{
SslStream ssl_connection = new SslStream(blabla.GetStream(), false, new RemoteCertificateValidationCallback(validate_certificate), null);
ssl_connection.AuthenticateAsClient("");
StreamReader ssl_stream = new StreamReader(ssl_connection);
ftp_writer = new StreamWriter(ssl_connection);
}
}
where validate_certificate is a function based on msdn's (you can google it and mod it easily yourself).
For more info see RFC 4217 and 2228.
http://ftps.codeplex.com/
This project contains every pieces you need.

Categories