Problem with multiple messages in TCP server [duplicate] - python

This question already has answers here:
How to properly use recv function for TCP chat, python3?
(1 answer)
How does socket recv function detects end of message
(1 answer)
Closed 1 year ago.
I apologize if this question seems trivial, but I'm a beginner at both C and programming with sockets. Also, english is not my native language.
I recently failed an uni assignment that asked me to implement a TCP server-client in C that accepts both ipv4 and ipv6, in which the client would send messages to add, remove, list and query pairs of ints from a linked list stored in the server. So, I made the server and the client with the codes below (not included are the code for the linked lists and for the function strsplit):
server (servidor.c)
void func(int sockfd)
{
struct Node* posts = NULL;
char client_message[MAX];
char server_message[MAX];
char* str;
char **p;
int X, Y, i, j, k;
int n = 0;
char sX[5];
char sY[5];
for (;;)
{
recv(sockfd, client_message, sizeof(client_message), 0);
printf("> %s", client_message);
strcpy(str, client_message);
p = strsplit(str, " ");
memset(server_message, 0, MAX);
if(strncmp("kill", p[0], 4) == 0)
{
break;
}
else if(strncmp("add", p[0], 3) == 0)
{
if(n == 50)
{
strncat(server_message, "limit exceeded", 14);
}
else
{
strncat(server_message, p[1], 4);
strncat(server_message, " ", 1);
X = atoi(p[1]);
strtok(p[2], "\n");
strncat(server_message, p[2], 4);
strncat(server_message, " ", 1);
Y = atoi(p[2]);
i = push(&posts, X, Y);
if(i == 0)
{
strncat(server_message, "added", 5);
n++;
}
else
{
strncat(server_message, "already exists", 14);
}
free(p);
}
}
else if(strncmp("rm", p[0], 2) == 0)
{
strncat(server_message, p[1], 4);
strncat(server_message, " ", 1);
X = atoi(p[1]);
strtok(p[2], "\n");
strncat(server_message, p[2], 4);
strncat(server_message, " ", 1);
Y = atoi(p[2]);
i = deleteNode(&posts, X, Y);
if(i == 0)
{
strncat(server_message, "removed", 7);
n--;
}
else
{
strncat(server_message, "does not exist", 14);
}
free(p);
}
else if(strncmp("list", p[0], 4) == 0)
{
if(posts == NULL)
{
strncat(server_message, "none", 4);
}
else
{
struct Node *temp = posts;
while(temp != NULL)
{
bzero(sX, 4);
bzero(sY, 4);
snprintf(sX, sizeof(sX), "%d",temp->X);
snprintf(sY, sizeof(sY), "%d",temp->Y);
strncat(server_message, sX, 4);
strncat(server_message, " ", 1);
strncat(server_message, sY, 4);
strncat(server_message, " ", 1);
temp = temp->next;
}
free(temp);
}
}
else if(strncmp("query", p[0], 5) == 0)
{
if(posts == NULL)
{
strncat(server_message, "none", 4);
}
else
{
struct Node *temp1 = posts;
k = 19998;
X = atoi(p[1]);
strtok(p[2], "\n");
Y = atoi(p[2]);
while(temp1 != NULL)
{
i = abs(temp1->X - X);
j = abs(temp1->Y - Y);
i = i + j;
if(i <= k)
{
snprintf(sX, sizeof(sX), "%d",temp1->X);
snprintf(sY, sizeof(sY), "%d",temp1->Y);
k = i;
}
temp1 = temp1->next;
}
strncat(server_message, sX, 4);
strncat(server_message, " ", 1);
strncat(server_message, sY, 4);
strncat(server_message, " ", 1);
free(temp1);
}
}
strncat(server_message, "\n", 1);
printf("%s", server_message);
send(sockfd, server_message, sizeof(server_message), 0);
}
}
int main(int argc, char *argv[])
{
if(strncmp("v4", argv[1], 2) == 0)
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(atoi(argv[2]));
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0)
{
exit(0);
}
if ((listen(sockfd, 5)) != 0)
{
exit(0);
}
len = sizeof(cli);
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0)
{
exit(0);
}
func(connfd);
close(sockfd);
}
else if(strncmp("v6", argv[1], 2) == 0)
{
int sockfd, connfd, len;
struct sockaddr_in6 servaddr, cli;
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
if(sockfd == -1)
{
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_addr = in6addr_any;
servaddr.sin6_port = htons(atoi(argv[2]));
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0)
{
exit(0);
}
if ((listen(sockfd, 5)) != 0)
{
exit(0);
}
len = sizeof(cli);
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0)
{
exit(0);
}
func(connfd);
close(sockfd);
}
return 0;
}
client (cliente.c)
void func(int sockfd)
{
char buff[MAX];
int n;
for (;;)
{
bzero(buff, sizeof(buff));
n = 0;
while ((buff[n++] = getchar()) != '\n')
;
send(sockfd, buff, sizeof(buff), 0);
if ((strncmp(buff, "kill", 4)) == 0)
{
break;
}
bzero(buff, sizeof(buff));
recv(sockfd, buff, sizeof(buff), 0);
printf("> %s", buff);
}
}
int main(int argc, char *argv[])
{
if(strchr(argv[1], ':') != NULL)
{
int sockfd, connfd;
struct sockaddr_in6 servaddr, cli;
struct in6_addr result;
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
if (sockfd == -1)
{
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
inet_pton(AF_INET6, argv[1], &result);
servaddr.sin6_addr = result;
servaddr.sin6_port = htons(atoi(argv[2]));
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
{
exit(0);
}
func(sockfd);
close(sockfd);
}
else
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(atoi(argv[2]));
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
{
exit(0);
}
func(sockfd);
close(sockfd);
}
return 0;
}
Testing on my own, by opening the server and the client in separate terminals and sending messages one by one, the server seemed to be working as intended. However, my professor says otherwise. After failing the assignment, he provided me with the python code of the software used to grade my server, which is as follows:
run_tests.py
def run_basic_tests(exec_path, version, port, msg_type):
address = '127.0.0.1' if version == 'v4' else '::1'
list_dir = os.listdir('tests/in')
list_dir = sorted(list_dir)
for filename in list_dir:
filename = filename.split('.')[0]
_, result_file_path = tempfile.mkstemp()
server = sp.Popen(
[f'exec {exec_path} {version} {port}'], shell=True, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
ret = os.system(
f'python3 client.py {address} {port} {msg_type} < tests/in/{filename}.in > {result_file_path}')
ret = os.WEXITSTATUS(ret)
if ret == 0:
if filecmp.cmp(f'tests/out/{filename}.out', result_file_path, shallow=False):
print(f'{filename}\t[OK]')
else:
print(f'{filename}\t[FAILED] (diff output)')
else:
print(f'{filename}\t[FAILED] (client exited with non-zero code {ret})')
os.remove(result_file_path)
server.kill()
if __name__ == '__main__':
if len(sys.argv) != 3:
print(f'usage: python3 {sys.argv[0]} <server> <port>')
sys.exit(0)
exec_path = sys.argv[1]
port = int(sys.argv[2])
if not exec_path.startswith('/'):
print('provide the full path to the executable')
sys.exit(0)
for address_family in ['v4', 'v6']:
for msg_type in ['single_msg_single_pkg', 'single_msg_multiple_pkg', 'multiple_msg_single_pkg']:
print('Testing IP' + address_family, msg_type)
run_basic_tests(exec_path, address_family, port, msg_type)
client.py
BUFFER = ''
def get_address_family(address):
try:
socket.inet_pton(socket.AF_INET, address)
return socket.AF_INET
except:
pass
try:
socket.inet_pton(socket.AF_INET6, address)
return socket.AF_INET6
except:
pass
sys.exit(1)
def create_socket(address, port):
address_family = get_address_family(address)
attempts = 0
client_socket = None
while attempts < 5:
try:
client_socket = socket.socket(address_family, socket.SOCK_STREAM)
client_socket.connect((address, port))
break
except socket.error:
client_socket = None
time.sleep(0.05)
attempts += 1
if not client_socket:
sys.exit(2)
return client_socket
# send one message
def send(client_socket, msg):
msg = msg.encode('ascii')
total_sent = 0
while total_sent != len(msg):
sent = client_socket.send(msg[total_sent:])
if sent == 0:
sys.exit(3)
total_sent += sent
# receive one complete message
def receive(client_socket):
global BUFFER
while True:
if '\n' in BUFFER:
msg = BUFFER[:BUFFER.index('\n')]
BUFFER = BUFFER[BUFFER.index('\n') + 1:]
return msg
try:
data = client_socket.recv(500 - len(BUFFER)).decode()
except socket.timeout:
sys.exit(7)
if not data:
sys.exit(4)
BUFFER += data
if len(BUFFER) >= 500:
sys.exit(5)
def run_multiple_msg_single_pkg(client_socket):
msg_buffer = []
for msg in sys.stdin:
msg_buffer.append(msg)
for i in range(0, len(msg_buffer), 2):
if i == len(msg_buffer) - 1:
send(client_socket, msg_buffer[i])
if msg_buffer[i] == 'kill\n':
client_socket.close()
sys.exit(0)
ret = receive(client_socket)
print(ret)
else:
msg = msg_buffer[i] + msg_buffer[i + 1]
send(client_socket, msg)
if msg_buffer[i] == 'kill\n':
client_socket.close()
sys.exit(0)
ret = receive(client_socket)
print(ret)
if msg_buffer[i + 1] == 'kill\n':
client_socket.close()
sys.exit(0)
ret = receive(client_socket)
print(ret)
def run_single_msg_multiple_pkg(client_socket):
for msg in sys.stdin:
send(client_socket, msg[:3])
time.sleep(0.1)
send(client_socket, msg[3:])
if msg == 'kill\n':
client_socket.close()
sys.exit(0)
ret = receive(client_socket)
print(ret)
def run_single_msg_single_pkg(client_socket):
for msg in sys.stdin:
send(client_socket, msg)
if msg == 'kill\n':
client_socket.close()
sys.exit(0)
ret = receive(client_socket)
print(ret)
if __name__ == '__main__':
if len(sys.argv) != 4:
print(
f'Usage: python3 {sys.argv[0]} <address> <port> [single_msg_single_pkg | single_msg_multiple_pkg | multiple_msg_single_pkg]')
sys.exit(6)
client_socket = create_socket(sys.argv[1], int(sys.argv[2]))
client_socket.settimeout(5)
if sys.argv[3] == 'single_msg_single_pkg':
run_single_msg_single_pkg(client_socket)
elif sys.argv[3] == 'single_msg_multiple_pkg':
run_single_msg_multiple_pkg(client_socket)
elif sys.argv[3] == 'multiple_msg_single_pkg':
run_multiple_msg_single_pkg(client_socket)
client_socket.close()
sys.exit(0)
Running my code with this software, none of the tests work. Basically, after receiving and sending the first message, my server halts communication with the client, failing every single test. This has probably something to do with how I'm treating the strings on my code, but honestly I'm at a loss here. Can someone at least give me a nudge in the right direction?

The main problem is that string that is send from python test application is not null-terminated, but you assume it is.
Here in python:
msg = msg.encode('ascii')
msg is encoded in ASCII format, but encode() method returns a bytes object which is not null-terminated, but when you receive it in your server:
recv(sockfd, client_message, sizeof(client_message), 0);
printf("> %s", client_message);
strcpy(str, client_message);
You have codes in your code that has assumed that what you have received in client_message is a null-terminated string. If you have zeroed client_message before recv(), you probably will not see this problem.
Bugs that I see in your code:
You assumed that messages are null-terminated. But it seems that they are supposed to be \n separated.
always check return of recv. you need to handle return values correctly. you may get error or you may get part of whole data.
In addition, run recv loop in a thread. although a suggestion, you normally always want to do this.

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);
}
}
}

back-and-forth unix domain sockets lock

I am writing two programs one in c++ and the other in Python to communicate with each other using unix domain sockets. What I am trying to do is have c++ code send a number to the python code, which in turn send another number back to c++. This goes on till c++ code runs out of numbers to send and the execution stops. Below are my codes. I can't seem to run them past the first iteration of the loop.
I run Python first:
python code.py /tmp/1 /tmp/2
Then I run the c++ code:
./code /tmp/1 /tmp/2
Here is the output:
C++ output:
sent 0
Listening
Connection successful
received 5
sent 1
Listening
Python output:
listening ...
received (0,)
>5
sent 5
listening ...
C++ Code:
static int connFd;
int main(int argc, char* argv[])
{
int recv_sock,
send_sock;
struct sockaddr_un server, client;
///////////////////////////////////////////
//
// setup send
//
///////////////////////////////////////////
/* Create socket on which to send. */
send_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (send_sock < 0)
{
perror("opening unix socket");
exit(1);
}
/* Construct name of socket to send to. */
client.sun_family = AF_UNIX;
strcpy(client.sun_path, argv[1]);
if (connect(send_sock, (struct sockaddr *) &client, sizeof(struct sockaddr_un)) < 0)
{
close(send_sock);
perror("connecting stream socket");
exit(1);
}
///////////////////////////////////////////
//
// setup recv
//
///////////////////////////////////////////
recv_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(recv_sock< 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char*) &server, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[2]);
//bind socket
if(bind(recv_sock, (struct sockaddr *)&server, sizeof(server)) < 0)
{
cerr << "Cannot bind" << endl;
return 0;
}
listen(recv_sock, 10);
int X;
for (int i = 0; i < 10; i++)
{
write(send_sock, &i, sizeof(i));
cout << "sent " << i << endl;
cout << "Listening" << endl;
connFd = accept(recv_sock, 0, 0);
if (connFd < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
cout << "Connection successful" << endl;
read(connFd, &X, sizeof(X));
cout << "received " << X << endl;
}
usleep(2000000);
}
close(send_sock);
close(recv_sock);
unlink(argv[2]);
unlink(argv[1]);
return 0;
}
Python Code:
import socket,os,struct, glob, sys
import random
send_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
recv_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(sys.argv[1])
except OSError:
pass
recv_socket.bind(sys.argv[1])
recv_socket.listen(10)
while 1:
print "listening ..."
conn, addr = recv_socket.accept()
data = conn.recv(4)
p = struct.unpack('i',data)
print 'received ', p
if p is '9':
break
l = int(raw_input(">"))
a = struct.pack('i', l)
send_socket.connect(sys.argv[2])
send_socket.sendall(a)
print 'sent ', l
send_socket.close()
conn.close()
recv_socket.close()
What am I doing wrong in this approach? Do I need to use threads?
Thanks
You handle differently the send and receive sockets in your C++ code: the send socket is bound once at the start of the program whereas the receive socket accepts a new connection at each iteration.
Your current Python implementation accepts a new connection on recv_socket and connects send_socket at each iteration which explains the issue that you are facing.
The most efficient fix would be to connect each socket once prior to the loop unless you have a good reason to open a new connection at each iteration. Here are the corresponding code listings:
C++
static int connFd;
int main(int argc, char *argv[]) {
int recv_sock, send_sock;
struct sockaddr_un server, client;
///////////////////////////////////////////
//
// setup send
//
///////////////////////////////////////////
/* Create socket on which to send. */
send_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (send_sock < 0) {
perror("opening unix socket");
exit(1);
}
/* Construct name of socket to send to. */
client.sun_family = AF_UNIX;
strcpy(client.sun_path, argv[1]);
if (connect(send_sock, (struct sockaddr *)&client,
sizeof(struct sockaddr_un)) < 0) {
close(send_sock);
perror("connecting stream socket");
exit(1);
}
///////////////////////////////////////////
//
// setup recv
//
///////////////////////////////////////////
recv_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (recv_sock < 0) {
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char *)&server, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[2]);
// bind socket
if (::bind(recv_sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
cerr << "Cannot bind" << endl;
return 0;
}
listen(recv_sock, 10);
connFd = accept(recv_sock, 0, 0);
if (connFd < 0) {
cerr << "Cannot accept connection" << endl;
return 0;
} else {
cout << "Connection successful" << endl;
}
int X;
for (int i = 0; i < 10; i++) {
write(send_sock, &i, sizeof(i));
cout << "sent " << i << endl;
cout << "Listening" << endl;
read(connFd, &X, sizeof(X));
cout << "received " << X << endl;
usleep(2000000);
}
close(send_sock);
close(recv_sock);
unlink(argv[2]);
unlink(argv[1]);
return 0;
}
Python
recv_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
send_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(sys.argv[1])
except OSError:
pass
recv_socket.bind(sys.argv[1])
recv_socket.listen(10)
conn, addr = recv_socket.accept()
send_socket.connect(sys.argv[2])
while 1:
print "listening ..."
data = conn.recv(4)
p = struct.unpack('i',data)
print 'received ', p
if p is '9':
break
l = int(raw_input(">"))
a = struct.pack('i', l)
send_socket.sendall(a)
print 'sent ', l
send_socket.close()
conn.close()
recv_socket.close()

Rate-limiting in python/arduino client/server communication

I'm trying to make a python client communicate with an arduino server. The python client asks the server to take a measurement from the sonar, and then server just sends a confirmation message and then takes the message.
The client:
client.py
import socket
import time
while True:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("192.168.0.250", 10220))
data = "GET\nSONAR\n\n"
print 'send to server: ' + data
client_socket.send(data)
receive = client_socket.recv(2048)
print receive
client_socket.close()
time.sleep(0.1)
except Exception as msg:
print msg
and the server:
server.ino
#include <avr/wdt.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
//localClient parameters, for sending data to the server.
byte mac[] = {0x90, 0xA2, 0xDA, 0x0F, 0x03, 0x58};
byte ip[] = {192,168,0,250};
byte server[] = {192, 168, 0, 100};
int serverPort = 8220;
//Server parameters, for acting like a server.
int pollPort = serverPort + 2000;
EthernetServer pollServer = EthernetServer(pollPort);
//char inString[32]; // string for incoming serial data
//sonar stuff
String content_string;
int NUM_SONARS = 1;
int sonarPin[] = {2, 3, 4, 5};
int triggerPin = 6;
int sonarThreshold = 12.0;
int sonarState[] = {0, 0, 0, 0};
long pulse;
int numPulses = 3;
int pulseArray[] = {0,0,0,0,0};
int filteredMode = 0;
float time;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
wdt_enable(WDTO_8S);
pollServer.begin();
for(int i = 0; i < NUM_SONARS; i++) {
pinMode(sonarPin[i], INPUT);
}
pinMode(triggerPin, OUTPUT);
digitalWrite(triggerPin, LOW);
time = 0;
}
void loop() {
wdt_reset();
time = millis();
EthernetClient pollClient = pollServer.available();
if (pollClient) {
boolean currentLineIsBlank = true;
String receivingString = "";
while (pollClient.connected()) {
//while the socket is open
if(pollClient.available()) {
//and there is something to read on the port, then read the available characters
char c = pollClient.read();
receivingString += c;
if (c == '\n' && currentLineIsBlank) {
Serial.print("String received -- ");
Serial.print(receivingString);
Serial.print("at ");
Serial.println(time);
pollClient.println("Received message.");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// parse the incoming data
String command = split(receivingString,'\n',0);
String payload = split(receivingString,'\n',1);
String key = split(payload,'=',0);
String value = split(payload,'=',1);
//PARSE THE KEY AND VALUE NOW
if(command == "GET") {
//if I received a GET command, send a response to the client.
if(key == "SONAR") {
pingSonars();
}
}
}
String split(String data, char delimiter, int index) {
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==delimiter || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void isort(int *a, int n) {
for (int i = 1; i < n; ++i) {
int j = a[i];
int k;
for (k = i - 1; (k >= 0) && (j < a[k]); k--) {
a[k + 1] = a[k];
}
a[k + 1] = j;
}
}
int mode(int *x,int n){
int i = 0;
int count = 0;
int maxCount = 0;
int mode = 0;
int bimodal;
int prevCount = 0;
while(i<(n-1)){
prevCount=count;
count=0;
while(x[i]==x[i+1]){
count++;
i++;
}
if(count>prevCount&count>maxCount){
mode=x[i];
maxCount=count;
bimodal=0;
}
if(count==0){
i++;
}
if(count==maxCount){//If the dataset has 2 or more modes.
bimodal=1;
}
if(mode==0||bimodal==1){//Return the median if there is no mode.
mode=x[(n/2)];
}
return mode;
}
}
void printArray(int *a, int n) {
for (int i = 0; i < n; i++)
{
Serial.print(a[i], DEC);
Serial.print(' ');
}
Serial.println();
}
void pingSonars() {
digitalWrite(6, HIGH);
for(int i = 0; i < NUM_SONARS; i++) {
for(int j = 0; j < numPulses; j++) {
pulse = pulseIn(sonarPin[i], HIGH);
pulseArray[j] = pulse/147; //convert to inches -- 147 uS per inches
delay(5);
}
isort(pulseArray, numPulses);
filteredMode = mode(pulseArray,numPulses);
//printArray(pulseArray,numPulses);
Serial.print("Filtered distance for Sonar ");
Serial.print(i);
Serial.print(": ");
Serial.println(filteredMode);
if((filteredMode < sonarThreshold) && !sonarState[i]) {
//if we are closer than the threshold and previously were not, this is a rising edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" triggered!");
sonarState[i] = 1;
}
else if (filteredMode > sonarThreshold && sonarState[i]) {
//if we are greater than the threshold and previously were, this is a falling edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" falling!");
sonarState[i] = 0;
}
}
}
The client sends requests at about a 100 millisecond interval, but the server seems to be able to respond much slower than that -- maybe at 2-3 times per second. What's limiting the rate of communication? Is it possible that the serial printouts are actually limiting it? Or does it have to do with how I'm opening/closing/listening to the port in the server code?
thanks for your help!

Parse a string in C and save it to an array of structs

I am quite familiar with Python coding but now I have to do stringparsing in C.
My input:
input = "command1 args1 args2 arg3;command2 args1 args2 args3;cmd3 arg1 arg2 arg3"
My Python solution:
input = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3"
compl = input.split(";")
tmplist =[]
tmpdict = {}
for line in compl:
spl = line.split()
tmplist.append(spl)
for l in tmplist:
first, rest = l[0], l[1:]
tmpdict[first] = ' '.join(rest)
print tmpdict
#The Output:
#{'command1': 'args1 args2 arg3', 'command2': 'args1 args2 args3', 'cmd3': 'arg1 arg2 arg3'}
Expected output: Dict with the command as key and the args joined as a string in values
My C solution so far:
I want to save my commands and args in a struct like this:
struct cmdr{
char* command;
char* args[19];
};
I make a struct char* array to save the cmd + args seperated by ";":
struct ari { char* value[200];};
The function:
struct ari inputParser(char* string){
char delimiter[] = ";";
char *ptrsemi;
int i = 0;
struct ari sepcmds;
ptrsemi = strtok(string, delimiter);
while(ptrsemi != NULL) {
sepcmds.value[i] = ptrsemi;
ptrsemi = strtok(NULL, delimiter);
i++;
}
return sepcmds;
Seperate commands and arrays by space and save them in my struct:
First I added a help struct:
struct arraycmd {
struct cmdr lol[10];
};
struct arraycmd parseargs (struct ari z){
struct arraycmd result;
char * pch;
int i;
int j = 0;
for (i=0; i < 200;i++){
j = 0;
if (z.value[i] == NULL){
break;
}
pch = strtok(z.value[i]," ");
while(pch != NULL) {
if (j == 0){
result.lol[i].command = pch;
pch = strtok(NULL, " ");
j++;
} else {
result.lol[i].args[j]= pch;
pch = strtok(NULL, " ");
j++;
}
}
pch = strtok(NULL, " ");
}
return result;
My output function looks like this:
void output(struct arraycmd b){
int i;
int j;
for(i=0; i<200;i++){
if (b.lol[i].command != NULL){
printf("Command %d: %s",i,b.lol[i].command);
}
for (j = 0; j < 200;j++){
if (b.lol[i].args[j] != NULL){
printf(" Arg %d = %s",j,b.lol[i].args[j]);
}
}
printf(" \n");
}
}
But it produces only garbage (Same input as in my python solution) :
(command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3 )
Command 0: command1 Arg 0 = command2 Arg 1 = args1 Arg 2 = args2 Arg 3 = arg3 Arg 19 = command2 Arg 21 = args1 Arg 22 = args2 Arg 23 = args3 Arg 39 = command3 Arg 41 = arg1 Arg 42 = arg2 Arg 43 = arg3
Segmentation fault
So I hope someone can help me to fix this.
check this solution . tested with valgrind no leak .
but i implemented printing inside freeing .u can implement by yourself looking at free function .further u can improve splitter function to achieve better parsing.
#include <stdio.h>
#include <stdlib.h>
typedef struct arr {
char** words;
int count;
} uarr;
#define null 0
typedef struct cmdr {
char* command;
char** argv;
int argc;
} cmd;
typedef struct list {
cmd* listcmd;
int count;
} cmdlist;
uarr splitter(char* str, char delim);
cmdlist* getcommandstruct(char* string);
void freecmdlist(cmdlist* cmdl);
int main(int argc, char** argv) {
char input[] = "command1 arg1 arg2 arg3 arg4;command2 arg1 arg2 ;command3 arg1 arg2 arg3;command4 arg1 arg2 arg3";
cmdlist* cmdl = getcommandstruct((char*) input);
//it will free . also i added print logic inside free u can seperate
freecmdlist(cmdl);
free(cmdl);
return (EXIT_SUCCESS);
}
/**
* THIS FUNCTION U CAN USE FOR GETTING STRUCT
* #param string
* #return
*/
cmdlist* getcommandstruct(char* string) {
cmdlist* cmds = null;
cmd* listcmd = null;
uarr resultx = splitter(string, ';');
//lets allocate
if (resultx.count > 0) {
listcmd = (cmd*) malloc(sizeof (cmd) * resultx.count);
memset(listcmd, 0, sizeof (cmd) * resultx.count);
int i = 0;
for (i = 0; i < resultx.count; i++) {
if (resultx.words[i] != null) {
printf("%s\n", resultx.words[i]);
char* def = resultx.words[i];
uarr defres = splitter(def, ' ');
listcmd[i].argc = defres.count - 1;
listcmd[i].command = defres.words[0];
if (defres.count > 1) {
listcmd[i].argv = (char**) malloc(sizeof (char*) *(defres.count - 1));
int j = 0;
for (; j < defres.count - 1; j++) {
listcmd[i].argv[j] = defres.words[j + 1];
}
}
free(defres.words);
free(def);
}
}
cmds = (cmdlist*) malloc(sizeof (cmdlist));
cmds->count = resultx.count;
cmds->listcmd = listcmd;
}
free(resultx.words);
return cmds;
}
uarr splitter(char* str, char delim) {
char* holder = str;
uarr result = {null, 0};
int count = 0;
while (1) {
if (*holder == delim) {
count++;
}
if (*holder == '\0') {
count++;
break;
};
holder++;
}
if (count > 0) {
char** arr = (char**) malloc(sizeof (char*) *count);
result.words = arr;
result.count = count;
//real split
holder = str;
char* begin = holder;
int index = 0;
while (index < count) {
if (*holder == delim || *holder == '\0') {
int size = holder + 1 - begin;
if (size > 1) {
char* dest = (char*) malloc(size);
memcpy(dest, begin, size);
dest[size - 1] = '\0';
arr[index] = dest;
} else {
arr[index] = null;
}
index++;
begin = holder + 1;
}
holder++;
}
}
return result;
}
void freecmdlist(cmdlist* cmdl) {
if (cmdl != null) {
int i = 0;
for (; i < cmdl->count; i++) {
cmd def = cmdl->listcmd[i];
char* defcommand = def.command;
char** defargv = def.argv;
if (defcommand != null)printf("command=%s\n", defcommand);
free(defcommand);
int j = 0;
for (; j < def.argc; j++) {
char* defa = defargv[j];
if (defa != null)printf("arg[%i] = %s\n", j, defa);
free(defa);
}
free(defargv);
}
free(cmdl->listcmd);
}
}
It may be easier to get your C logic straight in python. This is closer to C, and you can try to transliterate it to C. You can use strncpy instead to extract the strings and copy them to your structures.
str = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3\000"
start = 0
state = 'in_command'
structs = []
command = ''
args = []
for i in xrange(len(str)):
ch = str[i]
if ch == ' ' or ch == ';' or ch == '\0':
if state == 'in_command':
command = str[start:i]
elif state == 'in_args':
arg = str[start:i]
args.append(arg)
state = 'in_args'
start = i + 1
if ch == ';' or ch == '\0':
state = 'in_command'
structs.append((command, args))
command = ''
args = []
for s in structs:
print s
Your problem is that you are relying on the pointers in your structures to be initialised to NULL.
They will just be random values, hence the SEGV.
You are also printing 200 commands and 200 arguments when the structure only has 10 commands and 19 arguments.

How to get a python server to convert recvline to a string?

How can I convert the input from the client from the server to a string or some other data type. My server can print the recvline from clients but doesn't recognize it as a common data type...
void timing()
{
for (long i = 0; i < 200000000; i ++){
printf("");
}
}
int main(int argc, char **argv){
int i;
int sockfd;
struct sockaddr_in servaddr;
char sendline[MAXLINE];
char recvline[MAXLINE];
time_t start, finish, final;
start = clock();
timing(); // a function that takes a differential time based on the client
finish = clock();
final = (finish - start) / CLOCKS_PER_SEC;
printf("timing: %ld\n", final);
if (argc != 2){
perror("usage: tcpcli <IPaddress>");
exit(-1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
char ** temp = NULL;
char * timing = NULL;
strtol(timing, temp, final); //***Problem here
write(sockfd, timing, 5);
bzero(recvline, MAXLINE);
if (read(sockfd, recvline, MAXLINE) == 0){ //reads from server
perror("Server terminated!");
exit(-1);
}
fputs(recvline, stdout);

Categories