zamkniecie procesu po nazwie

0

Cześć. Mam problem z wysłaniem sygnału zamknięcia procesu z programu w języku C.

po numerze pid jest to tak:

kill(pid, SIGTERM) 

A jak będzie, żeby nie wpisywać numeru PID tylko nazwę? Bo nie mogę znaleźć :(

Z góry dziękuję za pomoc.
Pozdrawiam.

0

W katalogu /proc masz pidy, a w numerze cmdline masz teoretycznie nazwę procesu wywołania.

0

Głównie chodzi o to, ze mam włączone dwa programy o nazwie test.out. Jak je zamknąć z poziomu programu po nazwie? nazwę wystarczy mi jak wpiszę na sztywno.

0

Kryterium systemu operacyjnego nie jest "nazwa procesu" tylko PID i jedyne co możesz zrobić to wysłać do konkretnego procesu identyfikowanego numerem PID sygnał.

Nie ma w systemie operacyjnym metod, które pozwalałyby wysłać sygnał do "procesu o nazwie XXX" chociażby z tego powodu, że PID danego procesu jest unikalny w danym momencie działania, a nazwa nie.
Jedyne wyjście to grepowanie i selekcjonowanie pidów, a następnie wysyłanie do nich sygnałów, co chociażby robi pkill:

pkill -9 test.out

0

Z nudów ci napisałem, niby działa.

class psaux(object):
    def __init__(self):
        self.list = []
        self.open()

    def printf(self):
        for a in self.list:
            print 'PID: %s NAME: %s' % (a[0], a[1])

    def open(self):
        import os
        l = os.listdir('/proc')
        for a in l:
            if a.isdigit():
                str = '/proc/%s/comm' % a
                temp = open(str, 'rb').read()
                self.list.append((a, temp))


if __name__ == "__main__":
    a = psaux()
    a.printf()
0

Może bardziej szczegółowo opisze o co chodzi. Napisałem program do obsługi kolejek. Klient - Serwer. I teraz jest taka sprawa, że odpalam 1 serwer i kilku klientów, jeżeli klient wyśle słowo koniec to serwer kończy działanie oraz ten klient który wysłał to słowo. No ale trzeba jeszcze zamknąć jakoś tego drugiego klienta, i właśnie nie bardzo wiem jak..

0

@marnit: Te odpowiedzi, które tutaj dostajesz są specyficzne dla danego systemu operacyjnego. Dla Linuksa masz katalog /proc z katalogami o numerach zgodnych z PIDami procesów (patrz, kod powyżej). We FreeBSD masz dla C elegancką bibliotekę libprocstat: https://www.freebsd.org/cgi/man.cgi?query=libprocstat&sektion=3. W obu zapewne dałoby się to wyciągnąć ze struktur pracującego kernela przez urządzenie /dev/kmem - tego podejścia gorąco nie polecam. Nieważne, jak tego dokonasz za każdym razem przelatujesz po liście procesów i pobierasz PIDy tych, których nazwa Ci pasuje i do nich ślesz sygnał.

Edit:
niech klient śledzi stan połączenia. Jak mu się serwer rozłączy niech spróbuje się podłączyć jeszcze raz, jak to się nie uda - serwer zmarł koniec pracy.

Edit2:
albo niech przed końcem pracy roześle instrukcję zamknięcia dla pozostałych. Jeśli ten program ma działać na więcej niż jednej maszynie, to nie masz innej drogi.

0

Zrób getpid i prześlij pid procesu i jak kipnie proces to ten drugi popełni samobojstwo

A kipnięciem możesz tak zrobić.

int func(){
return 1;
}

exit:
func();
asm("int 0x80");
 
0
 int a = getpid(); // pid klienta
send(a); // wysyłasz do serwera
recv(b);
if (praca_end == true) kill(b); 
0

W sensie, że w serwerze mam dodać:

if(wiadomosc.dziala == 0)       
    kill(wiadomosc.adres, SIGTERM);
1
Smród napisał(a):

A kipnięciem możesz tak zrobić.

int func(){
return 1;
}

exit:
func();
asm("int 0x80");
 

Nie, nie może, bo chociaż to ma szansę zadziałać na konkretnym kompilatorze z wyłączoną optymalizacją, w innej wersji kompilatora albo pod innym kompilatorem może nagle przestać. Nie ma żadnej gwarancji że kompilator wygeneruje mov eax,1 w miejscu wywołania func(), bo o to chyba ci chodziło.

W ogóle najlepiej nie używać wstawek asm(), tylko jeśli ma być fragment kodu w asemblerze, umieścić go w osobnym pliku źródłowym .asm czy .s i napisać funkcję całą w asemblerze.

0

@marnit pytanie co dokładnie chcesz uzyskać. Bo możesz zrobić kilka rzeczy, np. w momencie kiedy serwer umiera wysyła pozostałym odbiorcom odpowiednią wiadomość, po otrzymaniu której się wyłączą.

Można mordować po nazwie. W Linuksie robi to killall, jakby jego kod źródłowy podejrzeć to tak naprawdę pobiera on tablicę procesów z ich numerami PID, a potem morduje każdego, który spełnia warunki wyrażenia regularnego iterując po tej tablicy zwykłym forem.

Wreszcie opcja nr 3: jeżeli te programy mają działać lokalnie, dopisz sobie jakiś launcher do nich, tak żeby tenże program rozruchowy stał się liderem grupy. Wtedy wysyłasz sygnał do PIDu 0 i cześć pieśni.

W każdym przypadki zastanów się tylko jak mądrze wyłączyć program i po nim posprzątać, tzn. pozamykać deskryptory itd. I uważaj co wołasz w handlerze sygnału, tam są dość spore ograniczenia.

0

Wrzucam, załącznik bo z tego pdf'a nie da się skopiować normalnie

@Edit

jeszcze coś takiego mam:

  • Zaimplementować problem "klient-serwer" z jednym serwerem i dowolną liczbą klientów przy użyciu mechamizmu kolejek komunikatów Uniksa (system V).
    -Korzystając w funkcji systemowych do kolejek komunikatów mechanizmu IPC stworzyć własną bibliotekę prostych funkcji do obsługi kolejek, podobnie jak w ćwiczeniu 6 dla semaforów.
    -Niech proces klient wysyła do kolejki komunikatów dowolny ciąg znaków, np. wpisywany z klawiatury, a proces serwer niech go odbiera z kolejki, zamienia w nim znaki na wielkie (upper-case) i odsyła z powrotem do klienta za pośrednictwem tej samej kolejki. Niech serwer wypisuje na ekranie tekst otrzymywany od klienta oraz tekst przetworzony, a klient niech wypisuje tekst odebrany od serwera. Spowalniać pracę serwera i klienta przy użyciu funkcji sleep().
    -W rozwiązaniu użyć tylko jednej kolejki komunikatów.
    -W celu rozróżniania w kolejce danych dla serwera oraz dla poszczególnych klientów zastosować odpowiednie etykietowanie komunikatów. Najlepiej z każdym komunikatem związać dwa identyfikatory (jako dwie pierwsze składowe struktury komunikatu): pierwszy odpowiadający procesowi adresata, a drugi procesowi nadawcy (pierwszy z nich powinien być umieszczony w polu typu komunikatu) - serwer przed odesłaniem klientowi odpowiedzi powinien zamienić miejscami te dwa identyfikatory. Identyfikatorem klienta może być jego PID, a za identyfikator serwera można przyjąć np. wartość 1. Trzecią składową struktury komunikatu powinien być przesyłany tekst jako tablica znakowa o ustalonym rozmiarze.
    -Niech proces serwer tworzy kolejkę komunikatów, a po zakończeniu działania wszystkich klientów niech ją usuwa. Można proces serwera kończyć np. sygnałem [Ctrl-C] z klawiatury, ale niech serwer przechwyci ten sygnał i obsłuży go w ten sposób, że przed swoim zakończeniem usunie kolejkę komunikatów.
    -Sygnałem zakończenia pracy dla klienta może być np. wysłanie z klawiatury znaku końca pliku EOF za pomocą sekwencji klawiszy[Ctrl-D].
0

To pokaż jeszcze jak zrobiłeś samą komunikację.

0

Moim zdaniem to zła droga, ale jak to mówią chcącemu się krzywda nie dzieje:
http://src.gnu-darwin.org/src/usr.bin/killall/killall.c.html
ogólnie to man sysctl

Alternatywnie iterujesz po katalogach w /proc i szukasz tam odpowiedniego pliku cmdline ale to może nie zadziałac na BSD np.

0

Zacznijmy od tego, że polecenie w zadaniu jest miejscami, delikatnie mówiąc, niemądre: "Niech proces serwer tworzy kolejkę komunikatów, a po zakończeniu działania wszystkich klientów niech ją usuwa". Skąd mamy wiedzieć, że wszyscy klienci się odłączyli? Interfejs nam tego nie umożliwia. Mamy implementować specjalny protokół nad msg z notyfikacjami o podłączaniu/odłączaniu klienta? Ktoś zrobił chyba copy-paste z zadania z TCP.

Opakowywanie msgctl, msgget, msgsnd i msgrcv jest nonsensem moim zdaniem. Po co mamy sobie zduplikować funkcjonalność err(3)? Dodatkowo, pokomplikuje nam to kod, bo rozpoznajemy sytuację errno==EINTR.

Odnośnie reszty, to moim zdaniem takie rozwiązanie jest wystarczająco poprawne:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/* Można też użyć ftok. */
#define KEY 0xDEADC0DE
#define MAX_LEN 256
#define ROLE_CLIENT 0x00
#define ROLE_SERVER 0x01

/*
 * Struktura używana przez nas do komunikacji.
 */
struct comm_msg {
	long mtype;
	struct msgbody{
		pid_t sender;
		char txt[MAX_LEN];
	} body;
};

/*
 * Pusta procedura na potrzeby obsługi SIGINT.
 */
static void
handle_sigint()
{
}

static void
run_client(const int msgid)
{
	struct comm_msg msg;

	printf("Enter message: ");
	while (fgets((char *)&msg.body.txt, sizeof(msg.body.txt), stdin) != NULL) {
		msg.mtype = ROLE_SERVER;
		msg.body.sender = getpid();

		if (msgsnd(msgid, &msg, sizeof(msg.body), 0) == -1)
			err(1, "msgrcv(2) failed");

		memset((void *)&msg.body.txt, '\0', sizeof(msg.body.txt));
		/* Odbieramy komunikaty wyłącznie adresowane do nas. */
		if (msgrcv(msgid, &msg, sizeof(msg.body), getpid(), 0) == -1)
			err(1, "msgrcv(2) failed");
		printf("Got: %sEnter message: ", msg.body.txt);
	}

	fprintf(stderr, "Client is exiting.\n");
}

static void
run_server(const int msgid)
{
	int i;
	struct comm_msg msg;

	for (;;) {
		if (msgrcv(msgid, &msg, sizeof(msg.body), ROLE_SERVER, 0) == -1) {
			if (errno != EINTR)
				err(1, "msgrcv(2) failed");
			else
				break;
		}

		i = 0;
		while (i < MAX_LEN && msg.body.txt[i] != '\0') {
			msg.body.txt[i] = toupper(msg.body.txt[i]);
			i++;
		}

		msg.mtype = msg.body.sender;
		msg.body.sender = ROLE_SERVER;
		/* XXX: tutaj też można dostać EINTR. */
		if (msgsnd(msgid, &msg, sizeof(msg.body), 0) == -1)
			err(1, "msgsnd(2) failed");

	}

	fprintf(stderr, "Server is exiting.\n");
	if (msgctl(msgid, IPC_RMID, NULL) == -1)
		err(1, "msgctl(2) failed");
}

int
main(int argc, char **argv)
{
	int msgid, role;

	msgid = msgget(KEY, 0600 | IPC_CREAT);
	if (msgid == -1)
		err(1, "msgget(2) failed");

	role = ROLE_SERVER;
	if (argc > 1) {
		if (strcmp(argv[1], "client") == 0) {
			role = ROLE_CLIENT;
		} else {
			fprintf(stderr, "Say what?\n");
			exit(1);
		}
	}
	/*
	 * W sumie to oba procesy powinny mieć ustawiony ten handler. Server
	 * zareaguje za pomocą EINTR zwróconego z msgrcv. Klient powinien
	 * reagować na Ctrl+D.
	 */
	if (signal(SIGINT, handle_sigint) == SIG_ERR)
		err(1, "signal(3) failed");

	if (role == ROLE_SERVER)
		run_server(msgid);
	else
		run_client(msgid);

	return (0);
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1