I have been trying to send data through C# to Python using socket.
I tried to program the sender using Python to make sure everything is set up properly using the Python code be
import socket
import sys
HEADERSIZE = 10
raw_msg = "a"
print(f"{len(raw_msg):<{HEADERSIZE}}"+raw_msg)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((socket.gethostname(), 1235))
s.listen(5)
clientsocket, address = s.accept()
print(f"Connection from {address} has been established.")
while True:
raw_msg = input("input: ")
msg = f"{len(raw_msg):<{HEADERSIZE}}"+raw_msg
clientsocket.send(bytes(msg,"utf-8"))
if raw_msg == "bye":
break
s.detach()
s.close()
When the code is executed, the packages sent look like:
b'39 readEx'
b'cel|x,test_Purch'
b'ase_Forecast.xls'
b'x'
b'45 printD'
b'ataFrames|x,test'
b'_Purchase_Foreca'
b'st.xlsx'
So, I did it using C# using the code below:
class Connection
{
int ServerPortNum;
Socket connectionSocket;
Socket welcomingSocket;
public Connection() {
ServerPortNum = 1235;
IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Loopback,ServerPortNum);
welcomingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
welcomingSocket.NoDelay = true;
Console.WriteLine("Starting");
welcomingSocket.Bind(serverEndPoint);
welcomingSocket.Listen(5);
}
public void Accept() {
connectionSocket = welcomingSocket.Accept();
}
public void send(string raw_msg_string)
{
char[] lengthCharArray = raw_msg_string.Length.ToString().ToCharArray();
string whiteSpace = String.Concat(Enumerable.Repeat(" ", 10-lengthCharArray.Length));
string header = new string(lengthCharArray) + whiteSpace;
Console.WriteLine(header + raw_msg_string);
byte[] msg = Encoding.ASCII.GetBytes(header + raw_msg_string);
connectionSocket.Send(msg);
}
public void ShutDown() {
connectionSocket.LingerState = new LingerOption(false, 0);
connectionSocket.Shutdown(SocketShutdown.Both);
connectionSocket.Disconnect(false);
connectionSocket.Close();
}
}
However the problem is C# is buffering the data it sends which is causing problems for my application. So, the send code for the same input looks like this:
b'39 readEx'
b'cel|x,test_Purch'
b'ase_Forecast.xls'
b'x45 print'
b'DataFrames|x,tes'
b't_Purchase_Forec'
b'ast.xlsx'
b''
So my question is, how can I prevent C# from buffering the data and cause it to send the package if the message is over instead of buffering it so that the packages look like the ones in python?
Related
I'm making an android app via android studio that displays accelerometer data on the screen and I tried to send this to my laptop via sockets, but the app closes by itself after sending this data once to my laptop.
here's a code sample of the socket class
public class MessageSender extends AsyncTask<String, Void, Void> {
Socket sock;
DataOutputStream dos;
PrintWriter pw;
#Override
protected Void doInBackground(String... voids) {
String message = voids[0];
try
{
sock = new Socket("192.168.0.105", 8400);
pw = new PrintWriter(sock.getOutputStream());
pw.write(message);
pw.flush();
}catch (IOException ioe){
ioe.printStackTrace();
}
return null;
}}
Here's the mainActivity code:
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private static final String TAG = "MainActivity";
private SensorManager sensorManager;
Sensor accelerometer;
MessageSender messenger = new MessageSender();
TextView xValue, yValue, zValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
xValue = (TextView) findViewById(R.id.xValue);
yValue = (TextView) findViewById(R.id.yValue);
zValue = (TextView) findViewById(R.id.zValue);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
#SuppressLint("SetTextI18n")
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Log.d(TAG, "onSensorChanged: X" + sensorEvent.values[0] + " Y: " +
sensorEvent.values[1] + " Z: " + sensorEvent.values[2]);
xValue.setText("X-axis: " + sensorEvent.values[0]);
yValue.setText("Y-axis: " + sensorEvent.values[1]);
zValue.setText("Z-axis: " + sensorEvent.values[2]);
messenger.execute("{\"X\":"+sensorEvent.values[0]+", \"Y\":"+sensorEvent.values[1]+", \"Z\":"+sensorEvent.values[2]+"}");
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}}
My laptop acts as the server with a python script, the code for which is below:
import socket
import json
TCP_IP = '192.168.0.105'
TCP_PORT = 8400
BUFFER_SIZE = 1024 # Normally 1024, but we want fast response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print('Connection address:', addr)
while 1:
data = conn.recv(BUFFER_SIZE)
parseData = json.loads(data)
if not data: break
print("received data:")
print(parseData)
conn.send(data) # echo
conn.close()
this is the error I'm getting on my python console:
received data:
{'X': -0.25576973, 'Y': -0.12328009, 'Z': 9.587313}
Traceback (most recent call last):
File "C:/Users/theva/Desktop/server.py", line 15, in <module>
data = conn.recv(BUFFER_SIZE)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
I'm trying to get the app to continuously send data to my pc as long as the connection is maintained else just display that data on the mobile screen
I'm probably doing this the wrong way but please help me with this, I don't mind criticism but just say it in simple layman terms please.
Thanks in advance!
messenger.execute("{"X":"+sensorEvent.values[0]+....
You can only call execute() once for an AsyncTask instance.
Dont use a global AsyncTask instance but create a new one for every message.
And if you want a permanent connection then use two async tasks. One to establish the connection. The other to send data.
I have a python socket server that receives a string from an Android app and should return the same string in uppercase. The app can send the string and I receive it in the server but how could I receive the returned string in the Android studio?
Here is my python code:
import socket
HOST = "127.0.0.1" # Standard loopback interface address (localhost)
PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
while True:
data = conn.recv(1024)
print(data)
if not data:
break
conn.sendall(data.upper())
Here is my sending message function
Socket s;
PrintWriter pw;
#Override
protected Void doInBackground(String... voids) {
String message = voids[0];
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try {
s = new Socket("10.0.2.2", Integer.parseInt("65432"));
//sending data
pw = new PrintWriter(s.getOutputStream());
pw.write(message);
pw.flush();
pw.close();
//////////
//receiving data
s.close();
} catch (IOException e) {
e.printStackTrace();
}
So I am trying to send data from the raspberry pi to unity.
I trying to create socket server to do so.
I can get the socket server running on the raspberry pi and can also look at the port with netstat -tulpn | grep :5005 in the terminal on the machine where the python script is running.
I also tried it on my mac and it also showed up as a TCP-server.
However when I try to connect to the same port and ip via Unity or on another machine it doesn't work. I also can't seem to find the port when listing all of the ports with netstat.
Unity spits out a "Connection refused" error.
Here is the code in Unity in C#
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;
public class ClientSocket : MonoBehaviour
{
bool socketReady = false;
TcpClient mySocket;
public NetworkStream theStream;
StreamWriter theWriter;
StreamReader theReader;
public String Host = "192.168.8.137";
public Int32 Port = 5005;
void Start()
{
setupSocket();
TextMessage("SocketTest");
}
public void setupSocket()
{ // Socket setup here
try
{
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e)
{
Debug.Log("Socket error:" + e); // catch any exceptions
}
}
public void TextMessage(string message)
{
if (socketReady == true)
{
theWriter.Write(message);
theWriter.Flush();
}
}
}
here is the code in python, which should be running on the raspberry pi.
import socket
import sys
backlog = 1
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.8.137', 5005))
s.listen(1)
try:
print ("is waiting")
client, address = s.accept()
while 1:
data = client.recv(size)
if data:
print (data)
finally:
print("closing socket")
cient.close()
s.close()
I'm new to socket servers, but I really trying to accomplish a connection here.
Thanks for reading!
am pretty sure you need to encode the data that you about to send in c# TcpClient
adding an example from my final project:
string data = "Hello Server!"; //the message in string (important it will be string)
byte[] msg = Encoding.Unicode.GetBytes(data); //encoded the message using unicode (utf-16)
NetworkStream stream = client.GetStream(); //get the tcp client stream
stream.Write(msg, 0, msg.Length); //write the message to the stream
and in the server you suppose to have something like that:
msg = clnt.recv(1024) #reciving the data
msg = msg.decode("utf-16") #decoding the data
print(msg) #printing the data
and i think thats it
and i would recommend using port above 10000 because most of the ports can be used
I'm trying to set up communication through a TCP/IP connection and are having problems with connecting the C# client to the Python Server.
It throws a SocketException:
System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it
I'm pretty sure that it is happening at the line where it tries to connect to the Python server: sender.Connect(remoteEP);
What I've tried
Before I used the IPv4 protocol and Pythons socket.AF_INET but I discovered that it seems like that my parsing of the IP Address in C# makes it an IPv6 address so that's what I'm using now but that didn't resolve the problem.
I also tried using IPAddress.Parse(ip) instead of getting the host first with Dns.GetHostEntry(ip) but that didn't seem to do anything.
The code
The C# code:
using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;
public class PyCommunicator : MonoBehaviour {
private string ip = "::1"; // Localhost
private int port = 14654;
public string dataStringToSend
{
get { return dataStringToSend; }
set { dataStringToSend = value; }
}
private void Start()
{
StartCoroutine(RequestServerCoroutine());
}
IEnumerator RequestServerCoroutine()
{
while (true)
{
RequestServer();
yield return new WaitForSecondsRealtime(10);
}
}
public void RequestServer()
{
byte[] bytes = new byte[1024]; // 1 KiloByte
try
{
// Connect to a Remote server,
// and get host IP Address that is used to establish a connection.
// In this case, we get one IP address of localhost that is IPv6 : ::1
// If a host has multiple addresses, you will get a list of addresses
IPHostEntry host = Dns.GetHostEntry(ip);
IPAddress ipAddress = host.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetworkV6,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
// Connect to Remote EndPoint
sender.Connect(remoteEP);
Debug.Log("Successfully established a connection between Unity and Python.");
// Encode the data string into a byte array.
dataStringToSend = "Test from C#";
if (dataStringToSend != "")
{
byte[] msg = Encoding.ASCII.GetBytes(dataStringToSend);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Reset.
dataStringToSend = "";
}
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Debug.LogFormat("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Debug.LogFormat("ArgumentNullException: {0}", ane.ToString());
}
catch (SocketException se)
{
Debug.LogFormat("SocketException: {0}", se.ToString());
}
catch (Exception e)
{
Debug.LogFormat("Unexpected exception: {0}", e.ToString());
}
}
catch (Exception e)
{
Debug.LogFormat("Exception from setup: {0}", e.ToString());
}
}
}
The C# code was taken from this link from the client section and modified for my own use.
Python code:
import socket
from time import sleep
class Communicator():
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.data_to_send = None
self.socket = None
self.socket_conn = None
self.socket_addr = None
# Start listening right away.
self.start()
def start(self):
"""Start listening and accept connection."""
self.socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.socket.bind((self.ip, self.port))
# Begin listening for 1 connection.
self.socket.listen(1)
print("Socket is listening on ip (" + str(self.ip) + ") and port " + str(self.port))
self.socket_conn, self.socket_addr = self.socket.accept()
print("Connection between Unity and Python established. Unity-C# is at: " + str(self.socket_addr))
sleep(5) # TESTING PURPOSES
# Receive.
result = ""
chunk_counter = 0
while True:
# Allow the server to read up to 1024 bytes.
data = self.conn.recv(1024)
chunk_counter += 1
# To minimize lag, read guess in chunks.
if chunk_counter < 5:
result += data.decode()
# If reading the guess is done,
# break out of loop.
if not data:
break
# Send.
self.socket.send("Test from python".encode())
# Close
self.socket.close()
def send_data(self):
"""Send data"""
pass
def receive_data(self):
"""Receive data"""
pass
Communicator('::1', 14654)
It seems like I didn't search the StackOverflow forum enough.
I found a solution in the code and answer given in this StackOverflow answer.
I didn't need to use the actual localhost loopback address and instead needed to get the HOSTNAME address through C#'s DNS function:
Dns.GetHostName()
I also used socket.gethostname() in Python so that they would have same addresses when connecting.
I also changed the whole thing to use IPv4 addresses and found out in the answer of the linked question that the first element in host.AddressList contains IPv6 addresses while the second AND last element contained IPv4 addresses, and that was the missing piece.
UPDATED CODE
C# Code:
using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;
public class PyCommunicator : MonoBehaviour {
private int port = 14654;
public string dataStringToSend
{
get { return dataStringToSend; }
set { dataStringToSend = value; }
}
private void Start()
{
StartCoroutine(RequestServerCoroutine());
}
IEnumerator RequestServerCoroutine()
{
while (true)
{
RequestServer();
yield return new WaitForSecondsRealtime(10);
}
}
public void RequestServer()
{
byte[] bytes = new byte[1024]; // 1 KiloByte
try
{
// Connect to a Remote server,
// and get host IP Address that is used to establish a connection.
// In this case, we get one IP address of localhost that is IP : 127.0.0.1
// If a host has multiple addresses, you will get a list of addresses
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = host.AddressList[1];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
// Connect to Remote EndPoint
sender.Connect(remoteEP);
Debug.Log("Successfully established a connection between Unity and Python.");
// Encode the data string into a byte array.
dataStringToSend = "Test from C#";
if (dataStringToSend != "")
{
byte[] msg = Encoding.ASCII.GetBytes(dataStringToSend);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Reset.
dataStringToSend = "";
}
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Debug.LogFormat("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Debug.LogFormat("ArgumentNullException: {0}", ane.ToString());
}
catch (SocketException se)
{
Debug.LogFormat("SocketException: {0}", se.ToString());
}
catch (Exception e)
{
Debug.LogFormat("Unexpected exception: {0}", e.ToString());
}
}
catch (Exception e)
{
Debug.LogFormat("Exception from setup: {0}", e.ToString());
}
}
}
Python Code:
import socket
from time import sleep
class Communicator():
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.data_to_send = None
self.socket = None
self.socket_conn = None
self.socket_addr = None
# Start listening right away.
self.start()
def start(self):
"""Start listening and accept connection."""
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((self.ip, self.port))
# Begin listening for 1 connection.
self.socket.listen(1)
print("Socket is listening on ip (" + str(self.ip) + ") and port " + str(self.port))
self.socket_conn, self.socket_addr = self.socket.accept()
print("Connection between Unity and Python established. Unity-C# is at: " + str(self.socket_addr))
sleep(5) # TESTING PURPOSES
# Receive.
result = ""
chunk_counter = 0
while True:
# Allow the server to read up to 1024 bytes.
data = self.conn.recv(1024)
chunk_counter += 1
# To minimize lag, read guess in chunks.
if chunk_counter < 5:
result += data.decode()
# If reading the guess is done,
# break out of loop.
if not data:
break
# Send.
self.socket.send("Test from python".encode())
# Close
self.socket.close()
def send_data(self):
"""Send data"""
pass
def receive_data(self):
"""Receive data"""
pass
Communicator(socket.gethostname(), 14654)
I am trying to establish a connection between an android phone(as server) and my computer(client in python) to send messages from the android phone to PC.
My Problem is that the app keeps crashing and I don't really know how to set the ip's.
So what I do is when the app opens I give it the computers IP and the port at which I need to send the message and then I click "send button".
Down below I have given the code that I have tried but the app crashes at the socket.send(sendPacket);
Android Code
public class MainActivity extends Activity {
private EditText ipInput;
private EditText portInput;
private EditText messageInput;
private Button sendButton;
private DatagramSocket socket;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ipInput = (EditText) findViewById(R.id.address);
portInput = (EditText) findViewById(R.id.port);
messageInput = (EditText) findViewById(R.id.message);
sendButton = (Button) findViewById(R.id.send);
sendButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String message = messageInput.getText().toString();
Log.e("TAG",message);
sendPacket(message);
}
});
}
private void sendPacket(String message) {
byte[] messageData = message.getBytes();
try {
InetAddress addr = InetAddress.getByName(ipInput.getText().toString());
int port = Integer.parseInt(portInput.getText().toString());
DatagramPacket sendPacket = new DatagramPacket(messageData, 0, messageData.length, addr, port);
if (socket != null) {
socket.disconnect();
socket.close();
return;
}
socket = new DatagramSocket(port);
socket.send(sendPacket);
} catch (UnknownHostException e) {
Log.e("MainActivity sendPacket", "getByName failed");
} catch (IOException e) {
Log.e("MainActivity sendPacket", "send failed");
}
}
#Override
public void onDestroy() {
super.onDestroy();
socket.disconnect();
socket.close();
}
}
Python Code:
My python code is also there, I bind the IP at 0.0.0.0 so I can get packet from anyone trying to communicate.
from socket import *
PORT = 7000
IP = "0.0.0.0"
sock = socket(AF_INET, SOCK_DGRAM) # SOCK_DGRAM means UDP socket
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.bind((IP, PORT))
while True:
print "Waiting for data..."
data, addr = sock.recvfrom(1024) # blocking
print "received: " + data
To sum it all up. I really need help with setting ip's, whose ip should I give to the android phone(the phone's or the laptops) and whose ip should I give to the laptop in the python code.
Secondly why does the app crash at "socket.send(sendPacket);" inside the send packet method.
If you need more details let me know in the comments.
So I can't answer you why the app is crashing but I can answer the IP question.
The client (laptop) needs the servers ip (in the same network its 192.168.X.XXX).
The server (phone) might also need his own ip.
The client might also need his own ip.
But notice that the server doesn't need the clients ip, it's open for all connections (except you want to white/black-list certain ip´s).
I did the same things with just some ip differences, works for me.
I have an app on which i press a button and it should turn on/off an led on a raspberry pi.
the code on android studio looks like this :
onPressed: () async {
setState(() {
instruction = power;
power = power == 'on' ? 'off' : 'on';
print('$instruction');
});
int port = 9999;
final socket = await EasyUDPSocket.bindBroadcast(port);
if (socket != null) {
socket.send(ascii.encode('$instruction'), '192.168.0.105', port);
final resp = await socket.receive();
print('Client $port received: $resp');
// `close` method of EasyUDPSocket is awaitable.
await socket.close();
print('Client $port closed');
}
},
the '192.168.0.105' is the ipv4 address of the raspberry pi(this can be found by typing "ipconfig" for windows in cmd and by "ifconfig" in an rpi)
the python code on the rpi or any pc will be
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
print("socket created")
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(("192.168.0.105",9999))
while True:
print("Waiting for data...")
data, addr = s.recvfrom(1024) # blocking
instruction = data.decode("utf-8")
if instruction == 'off':
print('turn off the led')
else:
print("turn on the led")
the python code is a bit customized for the led purpose but i'm sure you'll understand how to work with it!