My current application involves a C client sending a file to a Python server using TCP. It will produce a hash of the file and send the information back. I can get it to work with a python client but I am having issues migrating the client into C. The python server is still unfinished (it needs to convert the file size string to int, error checking, etc).
My biggest issue right now is after the server calls hash_type = connbuff.get_utf8(), it gives me the first user input of the hash type, then closes the connection. I know it is an issue with get_utf8(), but I am stumped on how to fix this. Should I just send arbitrary amounts of data from the client every time? Please help me learn from the error of my ways! Any advice/suggestions are much appreciated! Thanks =)
Server.py
import socket
import os
import hashlib
import buffer
HOST = '127.0.0.1'
PORT = 2345
def getHash(fileName, hashType):
... hash algorithms ....
try:
os.mkdir('uploads')
except FileExistsError:
pass
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
while True:
conn, addr = s.accept()
print("Got a connection from ", addr)
connbuf = buffer.Buffer(conn)
while True:
hash_type = connbuf.get_utf8()
if not hash_type:
break
print('Hash Type: ', hash_type)
file_name = connbuf.get_utf8()
if not file_name:
break
print('File Name: ', file_name)
file_name = os.path.join('uploads', file_name)
file_size = connbuf.get_utf8()
file_size = int(file_size)
print('File Size: ', file_size)
with open(file_name, 'wb') as f:
remaining = file_size
while remaining:
if remaining >= 4096:
chunk_size = 4096
else:
chunk_size = remaining
chunk = connbuf.get_bytes(chunk_size)
if not chunk:
break
f.write(chunk)
remaining -= len(chunk)
if remaining:
print('File incomplete: MISSING', remaining, 'BYTES.')
else:
print('File received successfully.')
file_hash = getHash(file_name, hash_type)
response = file_name + ' ' + file_hash
connbuf.put_utf8(response)
print('Connection closed.')
conn.close()
My Buffer class get_utf8() and get_bytes() look like this...
def __init__(self,s):
self.sock = s
self.buffer = b''
def get_bytes(self,n):
while len(self.buffer) < n:
data = self.sock.recv(1024)
if not data:
data = self.buffer
self.buffer = b''
return data
self.buffer += data
data,self.buffer = self.buffer[:n],self.buffer[n:]
return data
def get_utf8(self):
while b'\x00' not in self.buffer:
data = self.sock.recv(1024)
if not data:
return ''
self.buffer += data
data,_,self.buffer = self.buffer.partition(b'\x00')
return data.decode()
Client.c
#include <sys/socket.h>
... more includes ...
#define PORT_NUMBER 2345
#define SERVER_ADDRESS "127.0.0.1"
char *inputString(FILE* fp, size_t size){
... string input code ...
}
int main () {
int server_socket, connection_status;
struct sockaddr_in serverAddress;
char *hashType;
char *fileName;
char send_buffer[4000];
FILE * file_to_send;
int file_size;
/* Connect to Server */
... connect to server code ...
/* Get Hash an File User Input */
printf("Enter hash type: ");
hashType = inputString(stdin, 10);
printf("Hash type: %s\n", hashType);
printf("Enter file name: ");
fileName = inputString(stdin, 10);
printf("File Name: %s\n");
/* Send User Input */
send(server_socket, hashType, sizeof(hashType), 0);
send(server_socket, fileName, sizeof(fileName), 0);
/* Open File, Get Size, Convert to String */
file_to_send = fopen(fileName, "rb");
fseek(file_to_send, 0, SEEK_END);
file_size = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
int l = snprintf(NULL, 0, "%d", file_size);
char *str_file_size;
asprintf(&str_file_size, "%i", file_size);
printf("%s\n", str_file_size);
/* Send File Size and File */
send(server_socket, str_file_size, sizeof(str_file_size), 0);
while(!feof(file_to_send)) {
fread(send_buffer, 1, sizeof(send_buffer) - 1, file_to_send);
}
send(server_socket, send_buffer, sizeof(send_buffer), 0);
return 0;
}
get_utf8 expects to read a null-terminated UTF-8-encoded string from the socket. In the C code, you send sizeof(hashType). hashType is a pointer, so you are sending exactly 4 or 8 bytes (depending on 32- or 64-bit architecture). You probably need strlen(hashType)+1 (+1 for the NULL). Ditto for filename.
get_utf8 also reads until it sees a null. If it never sees one, it returns empty string, which then causes the receive code to break and closes the connection.
Related
I am trying to send a file from python client to a c# server and present it on screen by saving it first and then showing it on my MainWindow.
I came across a couple of problems I can't figure out why happen (I'm new to C#)
I followed this guide : http://snippetbank.blogspot.com/2014/04/csharp-client-server-file-transfer-example-1.html
The problems were :
1. The file was not being saved to my folder.
2. when I used message box to try and detect if it passes all the info it looks like it gets stuck in the middle .
I've been stuck on this for quite some time now but can't figure out what I'm missing
Python code :
def send_file(conn, name):
try:
full_path = "Output/"+name
file_to_send = open(full_path, "rb")
size = os.path.getsize(full_path)
file_name = name + "\n"
size_to_send = str(size) + "\n"
conn.send(size_to_send.encode())
conn.send(file_name.encode())
while size > 0:
data = file_to_send.read(1024)
conn.send(data)
size -= len(data)
file_to_send.close()
return conn
except IOError:
print("FILE IS ALREADY OPEN")
C# CODE :
public static string ReceiveFile(StreamReader reader, TcpClient tcpClient)
{
string folder = #"C:\Users\Roy\Desktop\GUI243\GUI243\";
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
MessageBox.Show(cmdFileSize);
// The first message from the client is the filename
string cmdFileName = reader.ReadLine();
MessageBox.Show(cmdFileName);
string full_path = folder + cmdFileName;
int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;
// Read bytes from the client using the length sent from the client
while (received < length)
{
remaining = length - received;
if (remaining < size)
{
size = remaining;
}
read = tcpClient.GetStream().Read(buffer, received, size);
if (read == 0)
{
break;
}
received += read;
}
// Save the file using the filename sent by the client
using (FileStream fStream = new FileStream(Path.GetFileName(cmdFileName), FileMode.Create))
{
fStream.Write(buffer, 0, buffer.Length);
fStream.Flush();
fStream.Close();
}
return full_path;
}
In your C# code looks like a while cycle is missing, unless you call the function ReceiveFile() iterating somewhere else.
The class StreamReader needs to constantly check the tcp client socket to see if new data has been received because this is how a TCP stream works.
You don't know when the client will connect and send the data so you can't just call the ReceiveFile() function once.
In the example there is a perpetual while (true) cycle that makes that reader.Readline() work:
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("Connected to client");
StreamReader reader = new StreamReader(tcpClient.GetStream());
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
...
}
Do you have an equivalent in your code?
Also, is not pratical to use MessageBox for debugging purposes.
Try:
Debug.WriteLine ("Expected size is: " + cmdFileSize);
Note you need System.Diagnostics to use that.
I have created a Python 3 sketch to try and upload the current NTP time to STM32L476RG Nucleo. The sketch is as follows:
import serial
import glob
import sys
import time
from socket import AF_INET, SOCK_DGRAM
import socket
import struct
def serial_ports():
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
print("OSError or Serial Exception raised, exiting...")
pass
return result
def getNTPTime(host = "pool.ntp.org"):
port = 123
buf = 1024
address = (host,port)
msg = '\x1b' + 47 * '\0'
# reference time (in seconds since 1900-01-01 00:00:00)
TIME1970 = 2208988800 # 1970-01-01 00:00:00
# connect to server
client = socket.socket( AF_INET, SOCK_DGRAM)
while True:
try:
client.sendto(msg.encode('utf-8'), address)
msg, address = client.recvfrom( buf )
t = struct.unpack( "!12I", msg )[10]
t -= TIME1970
return t
except (socket.gaierror):
print("Error! Internet connection not found, exiting...")
break
my_t_zone = -8
cur_ser = ''.join([s for s in serial_ports() if 'usbmodem' in s])
if(len(cur_ser)>0):
ser = serial.Serial(cur_ser)
if(not ser.isOpen()):
ser.open()
valid = 0
time.sleep(.5)
while(not valid):
ser.reset_input_buffer()
line = ser.readline().decode('utf-8').strip()
if(line=="Hello"):
ntp_time = ("DEA"+str(getNTPTime()+(my_t_zone*3600))+"L").encode('utf_8')
ser.write(ntp_time)
valid = 1
time.sleep(.5)
print("Done uploading time.")
ser.close()
else:
print("No compatible serial device found, exiting...")
The Mbed sketch running on the Nucleo board is as follows:
#include "mbed.h"
Serial pc(USBTX, USBRX);
const int kMaxBufferSize = 100;
char buffer[kMaxBufferSize];
int len = 0;
int contact = 1;
void removeChar(char *s, int c){
int j, n = strlen(s);
for (int i=j=0; i<n; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
}
int main()
{
pc.baud(9600);
while(contact) {
pc.printf("Hello\n");
if (pc.readable() > 0) {
char new_char;
while(new_char != 'L') {
new_char = pc.getc();
buffer[len++] = new_char;
}
contact = 0;
}
}
removeChar(buffer, 'D');
removeChar(buffer, 'E');
removeChar(buffer, 'A');
removeChar(buffer, 'L');
int x = atoi(buffer);
while(!contact) {
pc.printf("%s\n",buffer);
}
}
The behavior of the system is unstable. I observe several things:
Most of the time this code snippet works fine and Mbed shows
the uploaded Posix timestamp properly after parsing.
Sometimes erroneous characters are shown in the parsed timestamp (e.g. symbols and other characters)
Sometimes the entire posix timestamp is not shown by Mbed and gets cut out.
Also, you can see the Python code uploads three characters before the timestamp. These are used to make sure the code works most of the time (i.e. without them first two digits of timestamps get cut out most of the time).
Can anyone suggest what’s wrong? Seems like a sync issue.
I am working in a C program with sockets. I found a proxy python script which is working with my program:
import threading
import serial
import socket
def setup():
"""
This function sets up the variables needed, including the serial port,
and it's speed/port settings, listening socket, and localhost adddress.
"""
global clisock, cliaddr, svrsock, ser
# Change this to the COM port your XBee Cellular module is using. On
# Linux, this will be /dev/ttyUSB#
comport = '/dev/ttyAMA0'
# This is the default serial communication speed of the XBee Cellular
# module
comspeed = 9600
buffer_size = 4096 # Default receive size in bytes
debug_on = 0 # Enables printing of debug messages
toval = None # Timeout value for serial port below
# Serial port object for XBCell modem
ser = serial.Serial(comport,comspeed,timeout=toval)
# Listening socket (accepts incoming connection)
svrsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# Allow address reuse on socket (eliminates some restart errors)
svrsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
clisock = None
cliaddr = None # These are first defined before thread creation
addrtuple = ('localhost', 1881) # Address tuple for localhost
# Binds server socket to localhost (allows client program connection)
svrsock.bind(addrtuple)
svrsock.listen(1) # Allow (1) connection
def ComReaderThread():
"""
This thread listens on the defined serial port object ('ser') for data
from the modem, and upon receipt, sends it out to the client over the
client socket ('clisock').
"""
global clisock
while (1):
resp = ser.read() ## Read any available data from serial port
print("Received {} bytes from modem.".format(len(resp)))
clisock.sendall(resp) # Send RXd data out on client socket
print("Sent {} byte payload out socket to client.".format(len(resp)))
def SockReaderThread():
"""
This thread listens to the MQTT client's socket and upon receiving a
payload, it sends this data out on the defined serial port ('ser') to the
modem for transmission.
"""
global clisock
while (1):
data = clisock.recv(4096) # RX data from client socket
# If the RECV call returns 0 bytes, the socket has closed
if (len(data) == 0):
print("ERROR - socket has closed. Exiting socket reader thread.")
return 1 # Exit the thread to avoid a loop of 0-byte receptions
else:
print("Received {} bytes from client via socket.".format(len(data)))
print("Sending payload to modem...")
bytes_wr = ser.write(data) # Write payload to modem via UART/serial
print("Wrote {} bytes to modem".format(bytes_wr))
def main():
setup() # Setup the serial port and socket
global clisock, svrsock
if (not clisock): # Accept a connection on 'svrsock' to open 'clisock'
print("Awaiting ACCEPT on server sock...")
(clisock,cliaddr) = svrsock.accept() # Accept an incoming connection
print("Connection accepted on socket")
# Make thread for ComReader
comthread = threading.Thread(target=ComReaderThread)
comthread.start() # Start the thread
# Make thread for SockReader
sockthread = threading.Thread(target=SockReaderThread)
sockthread.start() # Start the thread
main()
I tried to do the same proxy script in C
#include "project.h"
#include <sys/socket.h>
#include <arpa/inet.h>
int fd,baudrate=9600,sock,new_socket;
struct sockaddr_in serv_addr, client;
int setup(){
int opt=1;
sock=0;
if(wiringPiSetup() <0) return 1;
if((fd=serialOpen("/dev/ttyAMA0",baudrate))<0) return 1;
printf("Serial communication opened \n");
fflush(stdout);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
printf("\n Socket creation error \n");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(1881);
int addrlen = sizeof(struct sockaddr_in);
if (bind(sock, (struct sockaddr *)&serv_addr, addrlen)<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(sock, 1) <0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("1\n");
addrlen=sizeof(struct sockaddr_in);
socklen_t sin_size=sizeof(struct sockaddr_in);
if ((new_socket = accept(sock, (struct sockaddr *)&client, &sin_size)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
char *client_ip = inet_ntoa(client.sin_addr);
printf("Accepted new connection from a client %s:%d\n", client_ip, ntohs(client.sin_port));
printf("1\n");
return 0;
}
PI_THREAD(socketRead){
int valread;
char buffer[4096]={0};
printf("hola %i\n",new_socket);
//Nos mantenemos a la escucha
for(;;){
//memset(buffer,0,sizeof(buffer));
//valread = recv( new_socket, buffer, 1024,0);
while((valread = read(new_socket,buffer,sizeof(buffer)-1))>0){
/*if ( valread < 0 ) {
printf ( "An error occured during the receive procedure \n" ) ;
return 0 ;
}*/
buffer[valread]=0;
printf("buffer %s\n",buffer);
write(fd,buffer,strlen(buffer));
}
}
}
PI_THREAD(uartRead){
int valread;
char buffer[4096]={0};
//Nos mantenemos a la escucha
for(;;){
//memset(buffer,0,sizeof(buffer));
valread = read( fd, buffer, sizeof(buffer));
//valread = read(new_socket,buffer,4096);
//send( new_socket, buffer,4096,0);
write(new_socket,buffer,sizeof(buffer));
printf("recibido\n");
}
}
int main(){
setup();
printf("adios %i\n",new_socket);
/* Thread creation */
piThreadCreate (socketRead);
piThreadCreate (uartRead);
for(;;){}
return 0;
}
I have not found differences between both programs, so my question is if there are any differences between Python and C libraries. With Python I am allow to see read the messages but in C I only receive 0x10 and 0x11. So, are there any differences between libraries or is something with my C script?
PI_THREAD(uartRead){
...
char buffer[4096]={0};
...
valread = read( fd, buffer, sizeof(buffer));
...
write(new_socket,buffer,sizeof(buffer));
In this code you read valread byte from the serial line but you always write 4096 byte (sizeof(buffer)). This means you send not only the data from the serial line but lots of junk data which are in the buffer.
The problem is thus not the difference between sockets in Python and C but just a bug in the C program.
I'm making an application using android and Python.
android is client
python is server
i send image file to python and want to receive string from server
but No strings are coming from the server.
socketIn.readLine() This part does not work.
try { // 소켓을 생성하고 입출력 스트립을 소켓에 연결
clientSocket = Socket(ip , port)
Log.d("Socket>>>>>>", "ip and port open Success!!!!!")
//val inputStream = clientSocket.getInputStream()
val tempfile = file
try{
socketIn = BufferedReader(InputStreamReader(clientSocket.getInputStream(), "UTF-8"))
//socketOut = PrintWriter(BufferedWriter(OutputStreamWriter(clientSocket.getOutputStream())),true)
dis = DataInputStream(FileInputStream(tempfile))
dos = DataOutputStream(clientSocket.getOutputStream())
val buf = ByteArray(1024)
var read_length : Int = 0
do {
read_length = dis.read(buf)
if(read_length == -1)
break
dos.write(buf)
dos.flush()
} while(read_length > 0)
var line : String?
var StringBuilder = StringBuilder()
do {
line = socketIn.readLine()
if(line == null)
break
StringBuilder.append(line)
}while(line != null)
onApiResult(line)
} catch (e : Exception){
Log.d("error", "${e}")
onApiFailed()
} finally {
clientSocket.close()
}
this is my android client code. client send the image to python server using tcp.
The image is sent well but the string does not come.
There is an error here line = socketIn.readLine()
please tell me how to fix it
from socket import *
serverPort = 8000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('123.234.345.456', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
msg = "hi"
while True:
connectionSocket, addr = serverSocket.accept()
img_file = open('hi.jpg', "wb")
while True:
sentence = connectionSocket.recv(1024)
data = sentence
img_file.write(sentence)
if sentence:
print("recving IMg....")
print(sentence)
sentence = connectionSocket.recv(1024)
img_file.write(sentence)
else:
print('Done')
img_file.close()
break
connectionSocket.sendall(bytes(msg, 'UTF-8'))
connectionSocket.close()
Just a guess -- you are sending binary data, but your client code uses java Reader/Writer classes (dedicated to reading text-like data). Use Streams, instead of Reader/Writer. There is no notion of 'endOfLine' when reading binary data. Also note, that client call to 'readLine()' assumes client platform dependent end-of-line, whatever it may be. If server and client platform differ, it will never work.
I am sending a double value from C through TCP using lwIP. To accomplish that, I am using an union between a double and one string of 8 bytes (because the lwIP's function to send data is of type 'char *'). Here te code:
void process_echo_request(void *p) {
int sd = (int)p;
int RECV_BUF_SIZE = 2048;
char recv_buf[RECV_BUF_SIZE];
int n, nwrote;
union {
double dval;
char sval[sizeof(double)];
} data_to_send;
data_to_send.dval = 1e+23;
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
data_to_send.dval += 1e+23;
/* handle request */
if ((nwrote = write(sd, data_to_send.sval, 8)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
I am trying to read from a Python script, but I fail on get the double value. The code:
#!/usr/bin/env python
import socket
from ctypes import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print float(data)
It fails with the message ValueError: could not convert string to float: �J��-�D
I know, is because the string is not a literal representation of a real value. Any idea? I need the real (double) value.
For more information, the lwIP echo server is running in a Zynq 7000 FPGA+SoC. I am running the Python code from a Debian 8. The double value is a 64 bit temperature for a sensor.
-- EDIT --
The final working code is:
#!/usr/bin/env python
import socket
from struct import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print unpack("d",data)[0]
you're recieving the binary representation of the double, not the string one.
You have to unpack it using struct module and the double specifier which is d. struct.unpack returns a tuple, so take first & only value to get your float
my_value = struct.unpack("d",data)[0]
note that you can even fix the endianness with < or >, not necessary if you're on the same machine or CPU type for both programs.