Two way communication between Unity and Python - python

So I want to send and receive from/to Unity and Python in the same run.
I have the following components for the communication.
TCPSendPipe - Sends data from Unity to Python
TCPListePipe - Receives data from Python
Python Script - Send (uses socket.connect) and Receive (uses socket.bind)
At the moment I can only use one at a time either,
TCPSendPipe with Python receive or,
TCPListenPipe with Python send
Following are the scripts:
TCPSendPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
public class TCPSendPipe : MonoBehaviour
{
public String Host = "localhost";
public Int32 Port = 55000;
TcpClient mySocket = null;
NetworkStream theStream = null;
StreamWriter theWriter = null;
public GameObject robot;
public Vector3 robPos;
// Start is called before the first frame update
void Start()
{
robot = GameObject.Find("robot");
mySocket = new TcpClient();
if (SetupSocket())
{
Debug.Log("socket is set up");
}
}
// Update is called once per frame
void Update()
{
robPos = robot.transform.position;
Debug.Log(robPos);
if (!mySocket.Connected)
{
SetupSocket();
}
sendMsg();
}
public void sendMsg()
{
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
//Byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes("yah!! it works");
Byte[] sendBytes = procData();
mySocket.GetStream().Write(sendBytes, 0, sendBytes.Length);
}
public bool SetupSocket()
{
try
{
mySocket.Connect(Host, Port);
Debug.Log("socket is sent");
return true;
}
catch (Exception e)
{
Debug.Log("Socket error: " + e);
return false;
}
}
public Byte[] procData()
{
Byte[] bytes = new Byte[12]; // 4 bytes per float
Buffer.BlockCopy( BitConverter.GetBytes( robPos.x ), 0, bytes, 0, 4 );
Buffer.BlockCopy( BitConverter.GetBytes( robPos.y ), 0, bytes, 4, 4 );
Buffer.BlockCopy( BitConverter.GetBytes( robPos.z ), 0, bytes, 8, 4 );
return bytes;
}
private void OnApplicationQuit()
{
if (mySocket != null && mySocket.Connected)
mySocket.Close();
}
}
TCPListenPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Globalization;
using System.Net.Sockets;
using UnityEngine;
public class TCPListenPipe : MonoBehaviour
{
public String Host = "localhost";
public Int32 Port = 55000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
private TcpListener listener = null;
private TcpClient client = null;
private NetworkStream ns = null;
string msg;
// Start is called before the first frame update
void Awake()
{
listener = new TcpListener(localAddr, Port);
listener.Start();
Debug.Log("is listening");
if (listener.Pending())
{
client = listener.AcceptTcpClient();
Debug.Log("Connected");
}
}
// Update is called once per frame
void Update()
{
if (client == null)
{
if (listener.Pending())
{
client = listener.AcceptTcpClient();
Debug.Log("Connected");
}
else
{
return;
}
}
ns = client.GetStream();
if ((ns != null) && (ns.DataAvailable))
{
StreamReader reader = new StreamReader(ns);
msg = reader.ReadToEnd();
float data = float.Parse(msg, CultureInfo.InvariantCulture);
Debug.Log(data);
}
}
private void OnApplicationQuit()
{
if (listener != null)
listener.Stop();
}
}
Python Script
import socket
import struct
import numpy as np
class comm(object):
TCP_IP = '127.0.0.1'
TCP_PORT = 55000
BUFFER_SIZE = 12 # Normally 1024, but we want fast response
conn = []
addr = []
s = []
def connect(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((self.TCP_IP, self.TCP_PORT))
self.s.listen(1)
self.conn, self.addr = self.s.accept()
print ('Connection address:', self.addr)
def receive(self):
byte_data = self.conn.recv(self.BUFFER_SIZE)
pos_data = np.array(np.frombuffer(byte_data, dtype=np.float32));
#print("bytes data:", byte_data)
print ("received data:", pos_data)
#conn.close()
return(pos_data)
def send(self):
cable_length = 25.123
MESSAGE = str(cable_length)
#MESSAGE = cable_length.tobytes()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.TCP_IP, self.TCP_PORT))
#s.send(MESSAGE)
s.send(MESSAGE.encode())
s.close()
return(MESSAGE)
So in order to send data from Unity to Python, I attach the TCPSendPipe.cs to the scene and within python script I just call receive after connecting.
comm_cl = comm()
comm_cl.connect()
while True:
data = comm_cl.receive()
Whereas to send data from Python to Unity, I have to detach TCPSendPipe.cs and attach TCPListenPipe.cs to the scene and within python script I just call send (without connect since connect has socket.bind).
send_data = aa.send()
My purpose is to have a 2 way communication between Unity and Python.
Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time?
Any suggestions or ideas on achieveing this is greatly appreciated.
Thank You.
Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time?

Related

Udp image transefing is too slow

I'm trying to send an image from C# to Python side via UDP. I split the image by 1024 bytes and send those chunks. On the Python side - I accept and merge them. The problem is speed. The image, which weighs about 200 KB, takes about 7 seconds to send. I read some questions about similar problems with UDP, but nothing helps. What can I do to speed up this connection? Thanks!
The sample image:
Python side:
import time
import threading
import socket
import traceback
import warnings
class ListenPort:
def __init__(self, port: int, is_camera: bool = False):
self.__port = port
self.__is_camera = is_camera
self.thread = None
self.__stop_thread = False
self.out_string = ""
self.out_bytes = b""
self.ip_end_point = ('127.0.0.1', self.__port)
self.sct = None
def start_listening(self):
self.thread = threading.Thread(target=self.listening, args=())
self.thread.start()
def listening(self):
self.sct = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("connected: " + str(self.__port))
while not self.__stop_thread:
try:
if self.__is_camera:
self.sct.sendto("Wait for size".encode('utf-16-le'), self.ip_end_point)
image_size, _ = self.sct.recvfrom(4)
print(len(image_size))
if len(image_size) < 4:
continue
buffer_size = (image_size[3] & 0xff) << 24 | (image_size[2] & 0xff) << 16 | \
(image_size[1] & 0xff) << 8 | (image_size[0] & 0xff)
self.sct.sendto("Wait for image".encode('utf-16-le'), self.ip_end_point)
local_bytes = b""
check_iters = 0
for i in range(0, buffer_size // 1024):
local_bytes += self.sct.recvfrom(1024)[0]
self.sct.sendto("Got data".encode('utf-16-le'), self.ip_end_point)
check_iters += 1
print(check_iters)
print(check_iters)
if buffer_size % 1024 > 0:
local_bytes += self.sct.recvfrom(buffer_size % 1024)[0]
self.out_bytes = local_bytes
else:
self.sct.sendto("Wait for data".encode('utf-16-le'), self.ip_end_point)
self.out_bytes, _ = self.sct.recvfrom(1024)
self.out_string = self.out_bytes.decode('utf-16-le')
except OSError:
break
except (Exception, EOFError):
traceback.print_exc()
print("disconnected: " + str(self.__port))
def reset_out(self):
self.out_string = ""
self.out_bytes = b""
def stop_listening(self):
self.__stop_thread = True
self.reset_out()
if self.sct is not None:
self.sct.shutdown(socket.SHUT_RDWR)
if self.thread is not None:
st_time = time.time()
while self.thread.is_alive():
if time.time() - st_time > 2:
warnings.warn("Something went wrong. Rude disconnection on port " + str(self.__port))
self.sct.close()
st_time = time.time()
listen = ListenPort(63213, True)
listen.start_listening()
st_time = time.time()
while True:
if len(listen.out_bytes) == 218669:
print("got image")
break
print(time.time() - st_time)
listen.stop_listening()
# the out of print(time.time() - st_time) is 7.35678505897522
C# side:
public struct Received
{
public IPEndPoint Sender;
public string Message;
}
public abstract class UdpBase
{
protected UdpClient Client;
protected UdpBase()
{
Client = new UdpClient();
}
public async Task<Received> Receive()
{
var result = await Client.ReceiveAsync();
return new Received()
{
Message = Encoding.Unicode.GetString(result.Buffer, 0, result.Buffer.Length),
Sender = result.RemoteEndPoint
};
}
}
public class TalkPortUdp : UdpBase
{
private bool stopTask = false;
private IPEndPoint _talkOn;
private string outString = "";
private byte[] outBytes = new byte[10];
public IPEndPoint sender;
public Task task;
public TalkPortUdp(IPEndPoint endpoint)
{
_talkOn = endpoint;
}
public void SetString(string data)
{
outString = data;
}
public void SetBytes(byte[] data)
{
outBytes = data;
}
public void Send(string message, IPEndPoint endpoint)
{
var datagram = Encoding.Unicode.GetBytes(message);
Client.Send(datagram, datagram.Length, endpoint);
}
public void SendBytes(byte[] message, IPEndPoint endpoint)
{
Client.Send(message, message.Length, endpoint);
}
public void StartTalking()
{
Client = new UdpClient(_talkOn);
stopTask = false;
task = Task.Run(() => {
while (!stopTask)
{
try
{
if (this.Client.Available > 0)
{
var received = this.Receive().GetAwaiter().GetResult();
string clientTask = received.Message;
sender = received.Sender;
if (clientTask.Contains("Wait for size"))
{
byte[] intBytes = BitConverter.GetBytes(outBytes.Length);
this.SendBytes(intBytes, received.Sender);
}
else if (clientTask.Contains("Wait for image"))
{
for (int i = 0; i < outBytes.Length - 1024; i += 1024)
{
byte[] second = new byte[1024];
Buffer.BlockCopy(outBytes, i, second, 0, 1024);
Console.WriteLine(i);
this.SendBytes(second, received.Sender);
received = this.Receive().GetAwaiter().GetResult();
}
int lastt = outBytes.Length % 1024;
if (lastt > 0)
{
byte[] lasttBytes = new byte[lastt];
Buffer.BlockCopy(outBytes, outBytes.Length - lastt, lasttBytes, 0, lastt);
this.SendBytes(lasttBytes, received.Sender);
}
}
else if (clientTask.Contains("Wait for data"))
{
this.Send(outString, received.Sender);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Console.WriteLine("Stopped");
});
}
public bool IsAlive()
{
if (task != null)
return task.Status.Equals(TaskStatus.Running);
return false;
}
public void StopTalking()
{
stopTask = true;
Client.Dispose();
Client.Close();
}
}
internal class Program
{
static void Main(string[] args)
{
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 63213);
TalkPortUdp talk = new TalkPortUdp(ipPoint);
talk.StartTalking();
while (true)
{
// Load file meta data with FileInfo
FileInfo fileInfo = new FileInfo(#"D:\Downloads\test_img.png");
// The byte[] to save the data in
byte[] data = new byte[fileInfo.Length];
// Console.WriteLine(fileInfo.Length);
// Load a filestream and put its content into the byte[]
using (FileStream fs = fileInfo.OpenRead())
{
fs.Read(data, 0, data.Length);
}
talk.SetBytes(data);
Thread.Sleep(1000);
}
}
}

Handshake Issues Tornado Server and ESP32 Client

I am unable to establish a websocket connection. I use an esp32 as an Client and an Tornado Webserver as Host.
I can connect to the Host with Javascript, but I can also connect the esp32 to websocket.org.
Only the connection between the esp32 and the Tornado Server doesn't work.
ESP32 Code (Arduino IDE):
#include <WiFi.h>
#include <WebSocketClient.h> //By Markus Sattler
const char* ssid = "hadome";
const char* password = "12345678";
char path[] = "/ws";
char host[] = "192.168.178.29";
WebSocketClient webSocketClient;
WiFiClient client;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(5000);
if (client.connect(host, 3333)) {
Serial.println("Connected");
} else {
Serial.println("Connection failed.");
}
webSocketClient.path = path;
webSocketClient.host = host;
if (webSocketClient.handshake(client)) {
Serial.println("Handshake successful");
} else {
Serial.println("Handshake failed.");
}
}
void loop() {
String data;
if (client.connected()) {
webSocketClient.sendData("Info to be echoed back");
webSocketClient.getData(data);
if (data.length() > 0) {
Serial.print("Received data: ");
Serial.println(data);
}
} else {
Serial.println("Client disconnected.");
}
delay(3000);
}
Python Code Excerpt (Tornado):
class WSHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def open(self):
pass
def on_message(self, message):
self.write_message(message)
def on_close(self):
log('[WS] Connection was closed.')
application = tornado.web.Application([(r'/ws', WSHandler)])
# Main program logic follows:
if __name__ == '__main__':
# Tornado Server
try:
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(3333)
http_client = tornado.httpclient.AsyncHTTPClient()
http_client.initialize(1)
log("Tornado Server started")
tornado.ioloop.IOLoop.current().spawn_callback(loop)
tornado.ioloop.IOLoop.instance().start()
except:
log("Exception triggered - Tornado Server stopped.")
finally:
pass
The ESP32 Program outputs:
.......
WiFi connected
IP address:
192.168.2.8
Connected
Waiting...
Handshake failed.
I am very confused because this javascript program works flawlessly (https://www.mischianti.org/2020/12/07/websocket-on-arduino-esp8266-and-esp32-client-1/):
var wsUri = "ws://192.168.178.29:3333/ws";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function (evt) {
onOpen(evt)
};
websocket.onclose = function (evt) {
onClose(evt)
};
websocket.onmessage = function (evt) {
onMessage(evt)
};
websocket.onerror = function (evt) {
onError(evt)
};
}
Sincerely Hannes
PS: Sorry for my bad english
I solved the problem by using another library. (I use the Library of Markus Sattler)

Slow communication between Wemos and Raspberry via WiFi

I have got PTZ controller, Wemos D1 Mini (based on ESP8266-12F) and Raspberry and I want read data from PTZ using Wemos and send it via wifi to Raspberry. This is my code on RPi:
import socket
s = socket.socket()
# host = socket.gethostname()
host = '192.168.0.26'
port = 9999
s.connect((host, port))
try:
while True:
response1 = s.recv(1024).decode("utf-8")
print(response1)
except KeyboardInterrupt:
s.close()
And my code on Wemos:
#include "ESP8266WiFi.h"
int msg = 0;
String str = String(0,HEX);
bool startReading = false;
String command = "";
const char *ssid = "MyName";
const char *password = "MyPassword";
WiFiServer wifiServer(9999);
void setup() {
Serial.begin(9600);
Serial.setDebugOutput(true);
for(uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] BOOT WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
delay(1000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting..");
}
Serial.print("Connected to WiFi. IP:");
Serial.println(WiFi.localIP());
wifiServer.begin();
}
void loop() {
WiFiClient client = wifiServer.available();
if (client) {
while (client.connected()) {
msg = Serial.read();
if (msg != -1) {
command = String(msg,HEX);
client.print(command);
}
delay(1);
}
client.stop();
Serial.println("Client disconnected");
}
}
Everything work fine, reaading data from PTZ is immediate but sending data to RPi is slow, I can see significant delay. Reducing the distance from the router does not improve the situation. I tried use #include <WebSocketsServer.h> but this libary is even worse. My question is how I can increase communication speed? Will putting the server on rpi instead of wemos help? Are there any more suitable libraries that I could use?

How to send the "token" as a header from a GUI application to at GET command in a flask service? [duplicate]

I have an HttpClient that I am using for a REST API. However I am having trouble setting up the Authorization header. I need to set the header to the token I received from doing my OAuth request.
I saw some code for .NET that suggests the following,
httpClient.DefaultRequestHeaders.Authorization = new Credential(OAuth.token);
However the Credential class does that not exist in WinRT. Anyone have any ideas how to set the Authorization header?
So the way to do it is the following,
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "Your Oauth token");
request.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
$"{yourusername}:{yourpwd}")));
I look for a good way to deal with this issue and I am looking at the same question. Hopefully, this answer will be helping everyone who has the same problem likes me.
using (var client = new HttpClient())
{
var url = "https://www.theidentityhub.com/{tenant}/api/identity/v1";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var response = await client.GetStringAsync(url);
// Parse JSON response.
....
}
reference from https://www.theidentityhub.com/hub/Documentation/CallTheIdentityHubApi
As it is a good practice to reuse the HttpClient instance, for performance and port exhaustion problems, and because none of the answers give this solution (and even leading you toward bad practices :( ), I put here a link towards the answer I made on a similar question :
https://stackoverflow.com/a/40707446/717372
Some sources on how to use HttpClient the right way:
https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
I suggest to you:
HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer <token>");
And then you can use it like that:
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
responseMessage = await response.Content.ReadAsAsync<ResponseMessage>();
}
In the case you want to send HttpClient request with Bearer Token, this code can be a good solution:
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new StringContent(".....", Encoding.UTF8, "application/json"),
RequestUri = new Uri(".....")
};
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "Your token");
var response = await _httpClient.SendAsync(requestMessage);
I was setting the bearer token
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
It was working in one endpoint, but not another. The issue was that I had lower case b on "bearer". After change now it works for both api's I'm hitting. Such an easy thing to miss if you aren't even considering it as one of the haystacks to look in for the needle.
Make sure to have "Bearer" - with capital.
Use Basic Authorization And Json Parameters.
using (HttpClient client = new HttpClient())
{
var request_json = "your json string";
var content = new StringContent(request_json, Encoding.UTF8, "application/json");
var authenticationBytes = Encoding.ASCII.GetBytes("YourUsername:YourPassword");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(authenticationBytes));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var result = await client.PostAsync("YourURL", content);
var result_string = await result.Content.ReadAsStringAsync();
}
For anyone finding this old thread now (2021), please look at this documentation about HttpClientFactory which is injectable and will also re-run on each request avoiding expired tokens which will make it useful for bearer tokens, generated clients, pooling etc.
TL;DR: Use HttpClientFactory and a DelegatingHandler which will act as middleware on all outgoing requests with your configured client.
This is how I add my bearer for Azure Identity (managed by Azure) but you can get the token however you want of course;
using Microsoft.Azure.Services.AppAuthentication;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class BearerTokenHandler : DelegatingHandler
{
public BearerTokenHandler(AzureServiceTokenProvider tokenProvider, string resource)
{
TokenProvider = tokenProvider;
Resource = resource;
}
public AzureServiceTokenProvider TokenProvider { get; }
public string Resource { get; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!request.Headers.Contains("Authorization"))
{
// Fetch your token here
string token = await TokenProvider.GetAccessTokenAsync(Resource);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
}
I configure my typed clients (generated with NSwag) like this in Startup;
var accessTokenProvider = new AzureServiceTokenProvider("<your-connection-string-for-access-token-provider>");
builder.Services.AddHttpClient<IOrdersClient, OrdersClient>().ConfigureHttpClient(async conf =>
{
conf.BaseAddress = new Uri("<your-api-base-url>");
}).AddHttpMessageHandler(() => new BearerTokenHandler(accessTokenProvider, "https://your-azure-tenant.onmicrosoft.com/api"));
Then you can inject your IOrdersClient wherever you like and all requests will have the bearer.
If you want to reuse the HttpClient, it is advised to not use the DefaultRequestHeaders as they are used to send with each request.
You could try this:
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new StringContent("...", Encoding.UTF8, "application/json"),
RequestUri = new Uri("...")
};
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"{user}:{password}")));
var response = await _httpClient.SendAsync(requestMessage);
To set basic authentication with C# HttpClient. The following code is working for me.
using (var client = new HttpClient())
{
var webUrl ="http://localhost/saleapi/api/";
var uri = "api/sales";
client.BaseAddress = new Uri(webUrl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.ConnectionClose = true;
//Set Basic Auth
var user = "username";
var password = "password";
var base64String =Convert.ToBase64String( Encoding.ASCII.GetBytes($"{user}:{password}"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",base64String);
var result = await client.PostAsJsonAsync(uri, model);
return result;
}
This is how i have done it:
using (HttpClient httpClient = new HttpClient())
{
Dictionary<string, string> tokenDetails = null;
var messageDetails = new Message { Id = 4, Message1 = des };
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:3774/");
var login = new Dictionary<string, string>
{
{"grant_type", "password"},
{"username", "sa#role.com"},
{"password", "lopzwsx#23"},
};
var response = client.PostAsync("Token", new FormUrlEncodedContent(login)).Result;
if (response.IsSuccessStatusCode)
{
tokenDetails = JsonConvert.DeserializeObject<Dictionary<string, string>>(response.Content.ReadAsStringAsync().Result);
if (tokenDetails != null && tokenDetails.Any())
{
var tokenNo = tokenDetails.FirstOrDefault().Value;
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + tokenNo);
client.PostAsJsonAsync("api/menu", messageDetails)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
}
}
}
This you-tube video help me out a lot. Please check it out.
https://www.youtube.com/watch?v=qCwnU06NV5Q
6 Years later but adding this in case it helps someone.
https://www.codeproject.com/Tips/996401/Authenticate-WebAPIs-with-Basic-and-Windows-Authen
var authenticationBytes = Encoding.ASCII.GetBytes("<username>:<password>");
using (HttpClient confClient = new HttpClient())
{
confClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(authenticationBytes));
confClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaType));
HttpResponseMessage message = confClient.GetAsync("<service URI>").Result;
if (message.IsSuccessStatusCode)
{
var inter = message.Content.ReadAsStringAsync();
List<string> result = JsonConvert.DeserializeObject<List<string>>(inter.Result);
}
}
UTF8 Option
request.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes(
$"{yourusername}:{yourpwd}")));
Using AuthenticationHeaderValue class of System.Net.Http assembly
public AuthenticationHeaderValue(
string scheme,
string parameter
)
we can set or update existing Authorization header for our httpclient like so:
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TokenResponse.AccessToken);
BaseWebApi.cs
public abstract class BaseWebApi
{
//Inject HttpClient from Ninject
private readonly HttpClient _httpClient;
public BaseWebApi(HttpClient httpclient)
{
_httpClient = httpClient;
}
public async Task<TOut> PostAsync<TOut>(string method, object param, Dictionary<string, string> headers, HttpMethod httpMethod)
{
//Set url
HttpResponseMessage response;
using (var request = new HttpRequestMessage(httpMethod, url))
{
AddBody(param, request);
AddHeaders(request, headers);
response = await _httpClient.SendAsync(request, cancellationToken);
}
if(response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<TOut>();
}
//Exception handling
}
private void AddHeaders(HttpRequestMessage request, Dictionary<string, string> headers)
{
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (headers == null) return;
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
private static void AddBody(object param, HttpRequestMessage request)
{
if (param != null)
{
var content = JsonConvert.SerializeObject(param);
request.Content = new StringContent(content);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
}
SubWebApi.cs
public sealed class SubWebApi : BaseWebApi
{
public SubWebApi(HttpClient httpClient) : base(httpClient) {}
public async Task<StuffResponse> GetStuffAsync(int cvr)
{
var method = "get/stuff";
var request = new StuffRequest
{
query = "GiveMeStuff"
}
return await PostAsync<StuffResponse>(method, request, GetHeaders(), HttpMethod.Post);
}
private Dictionary<string, string> GetHeaders()
{
var headers = new Dictionary<string, string>();
var basicAuth = GetBasicAuth();
headers.Add("Authorization", basicAuth);
return headers;
}
private string GetBasicAuth()
{
var byteArray = Encoding.ASCII.GetBytes($"{SystemSettings.Username}:{SystemSettings.Password}");
var authString = Convert.ToBase64String(byteArray);
return $"Basic {authString}";
}
}
In net .core you can use with Identity Server 4
var client = new HttpClient();
client.SetBasicAuthentication(userName, password);
or
var client = new HttpClient();
client.SetBearerToken(token);
see https://github.com/IdentityModel/IdentityModel/blob/main/src/Client/Extensions/AuthorizationHeaderExtensions.cs
this could works, if you are receiving a json or an xml from the service and i think this can give you an idea about how the headers and the T type works too, if you use the function MakeXmlRequest(put results in xmldocumnet) and MakeJsonRequest(put the json in the class you wish that have the same structure that the json response) in the next way
/*-------------------------example of use-------------*/
MakeXmlRequest<XmlDocument>("your_uri",result=>your_xmlDocument_variable = result,error=>your_exception_Var = error);
MakeJsonRequest<classwhateveryouwant>("your_uri",result=>your_classwhateveryouwant_variable=result,error=>your_exception_Var=error)
/*-------------------------------------------------------------------------------*/
public class RestService
{
public void MakeXmlRequest<T>(string uri, Action<XmlDocument> successAction, Action<Exception> errorAction)
{
XmlDocument XMLResponse = new XmlDocument();
string wufooAPIKey = ""; /*or username as well*/
string password = "";
StringBuilder url = new StringBuilder();
url.Append(uri);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url.ToString());
string authInfo = wufooAPIKey + ":" + password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Timeout = 30000;
request.KeepAlive = false;
request.Headers["Authorization"] = "Basic " + authInfo;
string documento = "";
MakeRequest(request,response=> documento = response,
(error) =>
{
if (errorAction != null)
{
errorAction(error);
}
}
);
XMLResponse.LoadXml(documento);
successAction(XMLResponse);
}
public void MakeJsonRequest<T>(string uri, Action<T> successAction, Action<Exception> errorAction)
{
string wufooAPIKey = "";
string password = "";
StringBuilder url = new StringBuilder();
url.Append(uri);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url.ToString());
string authInfo = wufooAPIKey + ":" + password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Timeout = 30000;
request.KeepAlive = false;
request.Headers["Authorization"] = "Basic " + authInfo;
// request.Accept = "application/json";
// request.Method = "GET";
MakeRequest(
request,
(response) =>
{
if (successAction != null)
{
T toReturn;
try
{
toReturn = Deserialize<T>(response);
}
catch (Exception ex)
{
errorAction(ex);
return;
}
successAction(toReturn);
}
},
(error) =>
{
if (errorAction != null)
{
errorAction(error);
}
}
);
}
private void MakeRequest(HttpWebRequest request, Action<string> successAction, Action<Exception> errorAction)
{
try{
using (var webResponse = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(webResponse.GetResponseStream()))
{
var objText = reader.ReadToEnd();
successAction(objText);
}
}
}catch(HttpException ex){
errorAction(ex);
}
}
private T Deserialize<T>(string responseBody)
{
try
{
var toReturns = JsonConvert.DeserializeObject<T>(responseBody);
return toReturns;
}
catch (Exception ex)
{
string errores;
errores = ex.Message;
}
var toReturn = JsonConvert.DeserializeObject<T>(responseBody);
return toReturn;
}
}
}
It may be easier to use an existing library.
For example, the extension methods below are added with Identity Server 4
https://www.nuget.org/packages/IdentityModel/
public static void SetBasicAuthentication(this HttpClient client, string userName, string password);
//
// Summary:
// Sets a basic authentication header.
//
// Parameters:
// request:
// The HTTP request message.
//
// userName:
// Name of the user.
//
// password:
// The password.
public static void SetBasicAuthentication(this HttpRequestMessage request, string userName, string password);
//
// Summary:
// Sets a basic authentication header for RFC6749 client authentication.
//
// Parameters:
// client:
// The client.
//
// userName:
// Name of the user.
//
// password:
// The password.
public static void SetBasicAuthenticationOAuth(this HttpClient client, string userName, string password);
//
// Summary:
// Sets a basic authentication header for RFC6749 client authentication.
//
// Parameters:
// request:
// The HTTP request message.
//
// userName:
// Name of the user.
//
// password:
// The password.
public static void SetBasicAuthenticationOAuth(this HttpRequestMessage request, string userName, string password);
//
// Summary:
// Sets an authorization header with a bearer token.
//
// Parameters:
// client:
// The client.
//
// token:
// The token.
public static void SetBearerToken(this HttpClient client, string token);
//
// Summary:
// Sets an authorization header with a bearer token.
//
// Parameters:
// request:
// The HTTP request message.
//
// token:
// The token.
public static void SetBearerToken(this HttpRequestMessage request, string token);
//
// Summary:
// Sets an authorization header with a given scheme and value.
//
// Parameters:
// client:
// The client.
//
// scheme:
// The scheme.
//
// token:
// The token.
public static void SetToken(this HttpClient client, string scheme, string token);
//
// Summary:
// Sets an authorization header with a given scheme and value.
//
// Parameters:
// request:
// The HTTP request message.
//
// scheme:
// The scheme.
//
// token:
// The token.
public static void SetToken(this HttpRequestMessage request, string scheme, string token);
Firstly, I wouldn't use HttpClient directly. It's too easy to make mistakes - particularly in the area of headers. The DefaultHeadersCollection is not immutable and not thread-safe because other parts of the app can change the headers on you. It's best to set the headers when you make the call. If you are working with an abstraction, and that is recommended because the classes in this area are a bit of a mess, you would want to have a headers collection and put those on your HttpRequestMessage before you send it. You need to make sure you put the content headers on the content, and not the message.
Code Reference
foreach (var headerName in request.Headers.Names)
{
//"Content-Type"
if (string.Compare(headerName, HeadersExtensions.ContentTypeHeaderName, StringComparison.OrdinalIgnoreCase) == 0)
{
//Note: not sure why this is necessary...
//The HttpClient class seems to differentiate between content headers and request message headers, but this distinction doesn't exist in the real world...
//TODO: Other Content headers
httpContent?.Headers.Add(HeadersExtensions.ContentTypeHeaderName, request.Headers[headerName]);
}
else
{
httpRequestMessage.Headers.Add(headerName, request.Headers[headerName]);
}
}
Here is a data structure that you could use to send the request which includes the headers.
Code Reference
public interface IRequest
{
CancellationToken CancellationToken { get; }
string? CustomHttpRequestMethod { get; }
IHeadersCollection Headers { get; }
HttpRequestMethod HttpRequestMethod { get; }
AbsoluteUrl Uri { get; }
}
public interface IRequest<TBody> : IRequest
{
TBody? BodyData { get; }
}
And, a headers collection:
Code Reference
public sealed class HeadersCollection : IHeadersCollection
{
#region Fields
private readonly IDictionary<string, IEnumerable<string>> dictionary;
#endregion
#region Public Constructors
public HeadersCollection(IDictionary<string, IEnumerable<string>> dictionary) => this.dictionary = dictionary;
public HeadersCollection(string key, string value) : this(ImmutableDictionary.CreateRange(
new List<KeyValuePair<string, IEnumerable<string>>>
{
new(key, ImmutableList.Create(value))
}
))
{
}
#endregion Public Constructors
#region Public Properties
public static HeadersCollection Empty { get; } = new HeadersCollection(ImmutableDictionary.Create<string, IEnumerable<string>>());
public IEnumerable<string> Names => dictionary.Keys;
IEnumerable<string> IHeadersCollection.this[string name] => dictionary[name];
#endregion Public Properties
#region Public Methods
public bool Contains(string name) => dictionary.ContainsKey(name);
public IEnumerator<KeyValuePair<string, IEnumerable<string>>> GetEnumerator() => dictionary.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => dictionary.GetEnumerator();
public override string ToString() => string.Join("\r\n", dictionary.Select(kvp => $"{kvp.Key}: {string.Join(", ", kvp.Value)}\r\n"));
#endregion
}
See all the working code and examples here.
You can too to use the follow exemple, that it use IHttpClientFactory:
readonly IHttpClientFactory _httpClientFactory;
public HTTPClientHelper(IHttpClientFactory httpClientFactory, string clientName = null)
{
this._httpClientFactory = httpClientFactory;
}
public Task<T> GetAsync(string url, string token) {
var client = _httpClientFactory.CreateClient(_clientName);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(JwtBearerDefaults.AuthenticationScheme, token);
using (HttpResponseMessage response = await _client.GetAsync(url)){
......
}
}
I came across this old thread. The problem I had was that I know to use a static HttpClient, but my token needs refreshing every 59 minutes.
So I could have used HttpClientFactory, but because one of my projects was still in .NET 4.8, I created a class that inherited from HttpClient so I have similar code in all projects. A secret is needed to be able to get the token (I'm using identityserver4).
I then set that as a singleton in DI (I'm using Ninject here):
Bind<MyHttpClient>().ToMethod(c =>
{
var accessKey = ConfigurationManager.AppSettings["AccessKey"];
var client = new MyHttpClient(accessKey)
{
BaseAddress = new Uri(MyUrls.MyApiBaseUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return client;
}).InSingletonScope();
Then the class itself - named after the API it is used to access:
public class MyHttpClient : BaseHttpClient
{
private static readonly HttpClient _authHttpClient = new HttpClient();
private string _secret;
public MyHttpClient(string secret)
{
_secret = secret;
}
/// <summary>
/// Add the token to each and every request, cached for 1 minute less than the token's lifetime
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var cacheSeconds = 3600 - 60; // Default of 59 minutes
var token = CacheHelper<string>.Get("MyToken", cacheSeconds * 60, () =>
{
var authorityUrl = MyUrls.AuthServerUrl;
// discover endpoints from metadata
DiscoveryDocumentResponse disco;
disco = _authHttpClient.GetDiscoveryDocumentAsync(authorityUrl).Result;
if (disco.IsError)
{
throw new Exception("Error getting discovery document: " + disco.Error);
}
// request token
var tokenResponse = _authHttpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "myapp",
ClientSecret = _secret,
Scope = "myapi"
}).Result;
if (tokenResponse.IsError)
{
throw new Exception("Error getting token: " + tokenResponse.Error);
}
if (tokenResponse.ExpiresIn < cacheSeconds + 60)
{
throw new Exception($"Token expires in {tokenResponse.ExpiresIn}s, which is less than {cacheSeconds + 60}");
}
if (tokenResponse.ExpiresIn > cacheSeconds + 60)
{
Log.Warn().Message($"Token expiry in {tokenResponse.ExpiresIn}s, which is greater than {cacheSeconds}").Write();
}
return tokenResponse.AccessToken;
});
// THIS IS THE BIT - Assign this inside a SendAsync override and you are done!
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
return base.SendAsync(request, cancellationToken);
}
}
Finally just for completeness, my CacheHelper class looks like this:
public static class CacheHelper<T>
{
private static readonly object _locker = new object();
public static T Get(string cacheName, int cacheTimeoutSeconds, Func<T> func)
{
var obj = MemoryCache.Default.Get(cacheName, null);
if (obj != null) return (T)obj;
lock (_locker)
{
obj = MemoryCache.Default.Get(cacheName, null);
if (obj == null)
{
obj = func();
var cip = new CacheItemPolicy
{
AbsoluteExpiration = new DateTimeOffset(DateTime.UtcNow.AddSeconds(cacheTimeoutSeconds))
};
MemoryCache.Default.Set(cacheName, obj, cip);
}
}
return (T)obj;
}
}
Oauth Process flow is complex and there is always a room for one error or another.
My suggestion will be to always use the boilerplate code and a set of libraries for OAuth authentication flow.It will make your life easier.
Here is the link for the set of libraries.OAuth Libraries for .Net
If you are using Visual Studio IISExpress debug mode and connecting to the HTTP port rather than the HTTPS port you may find that the auth headers are being dropped.
Switch to the SLL connection and they will appear again.
unsure why, possibly the setup redirects the http traffic and that causes the auth to be removed.
This may help Setting the header:
WebClient client = new WebClient();
string authInfo = this.credentials.UserName + ":" + this.credentials.Password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
client.Headers["Authorization"] = "Basic " + authInfo;
static async Task<AccessToken> GetToken()
{
string clientId = "XXX";
string clientSecret = "YYY";
string credentials = String.Format("{0}:{1}", clientId, clientSecret);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials)));
List<KeyValuePair<string, string>> requestData = new List<KeyValuePair<string, string>>();
requestData.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
FormUrlEncodedContent requestBody = new FormUrlEncodedContent(requestData);
var request = await client.PostAsync("https://accounts.spotify.com/api/token", requestBody);
var response = await request.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<AccessToken>(response);
}
}

cv2 incorrect image decode

I'm programming a Java client which sends an image as byte array and a Python server to receive the image. Received image height, width, channels are right,
sock = socket.socket()
sock.bind(('localhost', 8080))
sock.listen(1)
print ("Listen")
conn, addr = sock.accept()
print('Start server')
while True:
data = conn.recv(1024)
if not data:
break
img = cv2.imdecode(np.fromstring(io.BytesIO(data).getvalue(), dtype=np.uint8), 1)
np.save('snapshot.npy',img)
exit()
Showing the image using cv2.imshow('img', img) gives an incorrect result:
Java side:
public class Client implements Runnable {
private Socket socket;
private DataOutputStream out;
private String server;
private int port;
private ArrayList<ResponseListener> listeners = new ArrayList<>();
public void addListener(ResponseListener responseListener){
listeners.add(responseListener);
}
public void removeListeners(ResponseListener responseListener){
listeners.remove(responseListener);
}
Client(String server, int port) {
this.server = server;
this.port = port;
}
public void start(){
while(socket==null){
try {
socket = new Socket(server, port);
socket.setTcpNoDelay(true);
System.out.println("Ready");
listeners.forEach((listener)->listener.serverIsReady());
} catch (Exception ex) {
System.out.println("In thread " + ex.toString());
}
}
}
public void send(byte[] img) throws IOException {
out.write(img);
}
#Override
public void run() {
InputStreamReader in = null;
try {
in = new InputStreamReader(socket.getInputStream());
System.out.println(in);
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
System.out.println("in or out failed");
System.exit(-1);
}
int count = 0;
while (true) {
try {
int line = in.read();
count++;
if(count==4) {
listeners.forEach((listener)->listener.onSignDefined(String.valueOf(line)));
count=0;
}
} catch (Exception e) {
System.out.println("In loop " + e.toString());
System.exit(-1);
}
}
}
}
I solved problem. Solution really easy:
data = conn.recv(640*480*3)
640*480*3 - size of image

Categories