I'm trying to build a python client to interact with my C server. Here's the code for the client:
import socket
s = socket.socket()
s.connect(("127.0.0.1", 12209))
print "preparing to send"
s.send("2")
s.send("mmm2.com")
s.send("mypwd")
s.send("5120")
print "Sent data"
root = s.recv(256)
print root
When I run this code on the interactive shell (the GUI IDLE) of course line by line, everything runs very fine. But when i save this code in a file and try to run it, it hangs and stops responding according to windows, what's it that I'm just not doing?
If you type it line by line, the sent strings are likely received by the server one after another in separate recv() calls.
When you execute it in a script, all the send() calls run immediately after each other without delay and the server will probably receive all the data in one bulk in a single recv() call. So the server will see "2mmm2.commypwd5120", and maybe not handle that correctly. It might wait for more input from the client.
You will need some explicit separation between the values, for example newline characters, so that the server can parse the received data correctly.
Related
Problem
I would like to program an attachable command line interface for my daemon.
I developped a daemon running 24/7 on Linux Openwrt:
#!/bin/sh /etc/rc.common
START=98
USE_PROCD=1
PROCD_DEBUG=1
start_service() {
procd_open_instance
procd_set_param command "/myProgram"
procd_set_param respawn
procd_close_instance
}
I would like to add a debug user interfaces for test. So we could live tune some parameters/actions and print log. Something like the screen package.
Hence i want to create a command line interface for this daemon.
Research
Stdin/Stdout
Ideally i would like to write directly to the stdin of the daemon and read the stdout.
Daemon
Duplicate stdin to a file.
Duplicate stoud to a file.
Client
A launched C program by the tester.
It would relay stdin to stdinfile of daemon and stdoutfile of daemon to stdout.
Critic
That would be maybe the simplest way and I could read stdout.
I couldn't find any exemples, it makes me think i'm overlooking something.
Theres a risk I fill the flash by writing endlessly to the stdoutfile.
Pipes
The creation of 2 named pipe can be possible.
Daemon
The daemon would create a named input pipe and poll the pipe by making non blocking read.
A second output pipe is necessary to write the return of the command received.
Client
A launched C program by the tester.
It would relay stdin to input pipe and output pipe to stdout.
Critic
I don't know if I can properly redirect the stdout of the daemon to output pipe. Which means I wont be able to print the stdout logs but only specific cli coded response.
MessageQ
Same issues as pipe.
Sockets
Seems rather complex for a simple application.
Shared Memory
The paradigm does not seems appropriate.
Pty
Maybe something can be done with pseudo terminals but I don't understand them even after reading explanations: attach a terminal to a process running as a daemon (to run an ncurses UI)
Screen/Tmux
I don't have screen or tmux in my repository.
Question
What is the proper way to create a CLI for a daemon ? Where could I find an exemple ?
I would use a Unix domain stream socket, with the CLI thread in a blocking accept() until a connection is obtained.
These sockets are bidirectional, and you can write a trivial CLI application to read from standard input to the connected socket, and from the connected socket to standard output. (That same trivial CLI program could be used to redirect the output over e.g. SSH to ones local computer with much more storage, running the CLI program remotely using something like ssh -l username openwrt-device.name-or-address cli-program | tee local-logfile. OpenWrt devices often don't have suitable storage for log files, so this can be very useful.)
Use vdprintf() to implement your own printf() that writes to the connected CLI.
Because sockets are bidirectional, if you want to use locking –– for example, to avoid mixing logging output and CLI responses ––, use a mutex for writing; the read side does not need to take the mutex at all.
You cannot really use <stdio.h> FILE * stream handles for this, because its internal buffering can yield unexpected results.
Assuming your service daemon uses sockets or files, it can be very useful to reserve the file descriptor used for the bidirectional CLI connection, by initially opening /dev/null read-write (O_RDWR). Then, when the connection is accept()ed, use dup2() to move the accepted connection descriptor to the reserved one. When the connection is to be closed, use shutdown(fd, SHUT_RDWR) first, then open /dev/null, and dup that descriptor over the connection to be closed. This causes the connection to be closed and the descriptor to be reopened to /dev/null, in an atomic manner: the descriptor is never "unused" in between. (If it is ever close()d in a normal manner, another thread opening a file or socket or accepting a new connection may reuse that descriptor, causing all sorts of odd effects.)
Finally, consider using an internal (cyclic) buffer to store the most recent output messages. You do not need to use a human-readable format, you can use e.g. the first character (codes 1 to 254) to encode the severity or log level, keeping NUL (0) as the end-of-string mark, and 255 as the "CLI response" mark, so that your CLI program can use e.g. ANSI colors to color the output if output is a terminal. (For example, "\033[1;31m" changes output to bright red, and "\033[0m" returns the output back to normal/default. The \033 refers to a single character, code 27, ASCII ESC.) This can be very useful to efficiently indicate the priority/severity of each separate output chunk to the human user. The Linux kernel uses a very similar method in its kernel logging facility.
I have seen there are some questions about this topic, but none of the answers satisfied me. Here is the problem: I need to write two sockets (client and server), with the client having to send to the server an awk program with some lines of input. No problem in sending strings back and forth between the sockets. Supposing I have stored the program in a string command and the string I should pass to it in input, I have tried this:
execl("/usr/bin/awk", command, input, (char *)0);
And this works, the awk program runs and it writes on the server's stdout and stderr. Thing is, if there are lines with errors, I need to send these back to the client, which is pretty impossible since execl doesn't give me the chance to store its output in arrays. So, does anybody know a way to do this without using system and popen?
I have 2 files Client Side & Server Side
I send a string over the socket from client to server. I have to execute this string as one does in a terminal. The output of the command is to be displayed on the client side.
Server Side Code : this loop runs on each thread created by pthread_create
while((n=recv(sock,client_message,2000,0))>0)
{
send(sock,server_out,n,0);
}
I need to run the string i recieve in client_message as a terminal command and fetch the output of the command and send it back via the server_out string buffer.
How do i go about this ?
So - you have two or three different tasks to accomplish.
The first one is to run the command line you received on the server. For that, you can start reading the system() function. It's very straightforward to use.
But then you need to get it's output. You can read about this two points in this question.
Lastly, send that data back to the server - once you have the output stream, it's just send()ing that via the socket. You can implement some mini-protocol for telling the other side how many bytes to expect, some error detection/correction if you want, etc.
Once the data arrives the client, then you can do whatever you want with it - print it on the screen, save to a file, you name it.
Read about this things, take your chances, and come back to continue asking if you need it - good luck!
So I have this old, nasty piece of C code that I inherited on this project from a software engineer that has moved on to greener pastures. The good news is... IT RUNS! Even better news is that it appears to be bug free.
The problem is that it was designed to run on a server with a set of start up parameters input on the command line. Now, there is a NEW requirement that this server is reconfigurable (didn't see that one coming...). Basically, if the server receives a command over UDP, it either starts this program, stops it, or restarts it with new start up parameters passed in via the UDP port.
Basically the code that I'm considering using to run the obfuscated program is something like this (sorry I don't have the actual source in front of me, it's 12:48AM and I can't sleep, so I hope the pseudo-code below will suffice):
//my "bad_process_manager"
int manage_process_of_doom() {
while(true) {
if (socket_has_received_data) {
int return_val = ParsePacket(packet_buffer);
// if statement ordering is just for demonstration, the real one isn't as ugly...
if (packet indicates shutdown) {
system("killall bad_process"); // process name is totally unique so I'm good?
} else if (packet indicates restart) {
system("killall bad_process"); // stop old configuration
// start with new parameters that were from UDP packet...
system("./my_bad_process -a new_param1 -b new_param2 &");
} else { // just start
system("./my_bad_process -a new_param1 -b new_param2 &");
}
}
}
So as a result of the system() calls that I have to make, I'm wondering if there's a neater way of doing so without all the system() calls. I want to make sure that I've exhausted all possible options without having to crack open the C file. I'm afraid that actually manipulating all these values on the fly would result in having to rewrite the whole file I've inherited since it was never designed to be configurable while the program is running.
Also, in terms of starting the process, am I correct to assume that throwing the "&" in the system() call will return immediately, just like I would get control of the terminal back if I ran that line from the command line? Finally, is there a way to ensure that stderr (and maybe even stdout) gets printed to the same terminal screen that the "manager" is running on?
Thanks in advance for your help.
What you need from the server:
Ideally your server process that you're controlling should be creating some sort of PID file. Also ideally, this server process should hold an exclusive lock on the PID file as long as it is still running. This allows us to know if the PID file is still valid or the server has died.
Receive shutdown message:
Try to get a lock on the PID file, if it succeeds, you have nothing to kill (the server has died, if you proceed to the kill regardless, you may kill the wrong process), just remove the old PID file.
If the lock fails, read the PID file and do a kill() on the PID, remove the old PID file.
Receive start message:
You'll need to fork() a new process, then choose your flavor of exec() to start the new server process. The server itself should of course recreate its PID file and take a lock on it.
Receive restart message:
Same as Shutdown followed by Start.
I'm doing a lab assignment where we make a Server program and a Client program. Its on the QNX OS. Not sure if it runs in Linux. The outline is this:
"Write a pair of C programs msgSender.c and msgLogger.c to demonstrate Neutrino message passing between processes.
Your programs will be called from the shell as:
$ msgLogger logFileName
$ msgSender msgLogger
logFileName is the name of the log that stores the messages
The msgLogger process acts as a logger. It receives messages and writes the messages to a file.
msgLogger receives text-based messages of the format shown in msg.h. It must test the message header and only write message text to the logFile if the message type is MSG_DATA.
If MSG_DATA is received, the reply status is MSG_OK.
If a MSG_END is received, the server replies with a status of MSG_END and then cleans up and exits.
If the received message is not MSG_DATA or MSG_END, the reply status is MSG_INVALID and the message text is not logged. A warning message is logged.
This process advertises its presence by writing its ND PID CHID to a file named msgLogger.pid where the "msgLogger" part of the filename is taken from argv[0].
The logged messages are stamped with the time and the ND PID COID of the sender.
The msgSender is an interactive program that assembles and sends the text-based message.
Reads the name of the logger process from the command line and uses this name to build the name of the .pid file where it reads the ND PID CHID.
It prompts the user for the message header type and then for the text of the message.
It will exit if it receives a MSG_END from the server.
It prints a warning if MSG_INVALID is received from the server
Your client and server must interoperate with my client and server.
Validate that the server works properly with multiple concurrent clients.
If you flush your server's file write buffer after each logging message, you can run it in the background and use
$ tail -f logFile
to view the messages as they are received.
Be sure to check the validity of the command-line argument.
Use global variables only when necessary.
"
I've got the msgLogger fully working; here is the code:
http://pastebin.com/8AGfGZ5u
And here is the msg.h file:
http://pastebin.com/3xcBZvnH
And here is the code I have so far for msgSender:
http://pastebin.com/Buk88Kry
What the sender (client) needs to do, is let the user enter the message type using digits. The msg.h file contains the type of message numbers with MSG_DATA being 1, etc. If they enter an invalid digit, it'll ask them to try again, else it will store that digit and assign it to the amsg.m_hdr of the MESSAGE struct. amsg.m_data is the value with the message.
Then the user enters the message they want, and if they chose the digit 1 (msg_data), the server sends notification and the client prints "message successfully received", while the contents of the message are saved to the log file.
Unfortunately I'm having a bunch of problems and it's not logging the message. I have to hand in the msgSender tomorrow, and it's also dependent on my next lab. I really hope I can get some help on this.
Try flushing the buffer after the client writes. If you don't close the file descriptor while writing to the file, there's no gaurentee that the buffer was flushed and the file was written. You can ensure that all your writes sync to the file whne you want by calling fsync().