Witam,
Czy mógłby mi ktoś powiedzieć jak przesłać wartość "string" z programu napisanego w C++ do programu napisanego w Pascal'u?
Jaki system operacyjny?
I co właściwie chcesz osiągnąć, bo o wiele łatwiej jest napisać program EXE w jednym języku, a bibliotekę DLL w drugim, niż rzeczywiście zrobić komunikację międzyprocesową (hint: hasło do szukania w Google)
Pomyłka
Chodziło mi o przesłanie "ciągu znaków" między z aplikacją napisaną w C++ do aplikacji napisanej w Pythonie.
Nie chodzi mi o napisanie biblioteki w jednym i z drugiego odczytania tej biblioteki tylko przesłanie informacji pomiędzy nimi.
System: Linux Debian
- plik
- tcp
- pipe
A mógłby ktoś napisać przykładowy kod wysyłania(c++) i odbierania informacji(python), tcp lub pipe( przez pliki raczej nie bo informacja co 0,2s jest nowa), bo zbytnio nie rozumiem przykładów z google.
A mógłby ktoś napisać przykładowy kod wysyłania(c++) i odbierania informacji(python)
Gniazda TCP sa dosc rozwkleklym tematem (jak i cala komunikacja miedzyprocesowa), wiec zaczniemy od poczatku:
- Polaczenie TCP odbywa sie w sposob zwany uzgadnianiem trojfazowym, a to dlatego, ze trzeba wyslac conajmniej 3 segmenty, zeby je sfinalizowac.
-
Serwer wykonuje otwarcie bierne, wywoluje funkcje bind(), listen() oraz accept().
bind() -> dowiazuje do gniazda adres oraz numer portu.
listen() -> przeksztalca gniazdo w gniazdo nasluchujace.
accept() -> usypia program dopoki w kolejce polaczen nie znajdzie sie jakis klient. -
Klient natomiast wykonuje otwarcie aktywne, poprzez wywolanie funkcji connect()
-
[ Polaczenie to jest realizowane przez wysylanie / odbieranie segmentow SYN oraz segmentow ACK dla uprzednich segmentow SYN, dodatkowo sa tez wysylane ustalone opcje gniazd jak MSS, zachecam do poczytania o tym ;)]
- Zakonczenie polaczenia TCP odbywa sie przy transmisji 4 segmentow (FIN, ACK dla FIN). Dodatkowo warto wiedziec, ze wszystkie otwarte deskryptory w systemie Unix sa zamykane wraz z wyjsciem programu, czy poprzez exit() czy poprzez kill(), czy jakkolwiek inaczej.
Dobra, ale skonczmy z teoria ;) Na pierwszy ogien pojdzie serwer napisany w C.
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ate()
{
printf("%d\n", errno);
}
int main()
{
int listenfd, connfd, rbytes;
struct sockaddr_in serv;
char buffer[1024];
const int PORT = 9980;
atexit(ate);
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
exit(-1);
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(PORT);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listenfd, (struct sockaddr*)&serv, sizeof(serv)) < 0)
exit(-1);
if(listen(listenfd, 10) < 0)
exit(-1);
while(1)
{
if((connfd = accept(listenfd, NULL, NULL)) < 0)
exit(-1);
while((rbytes = recv(connfd, buffer, sizeof(buffer), 0)) > 0)
{
buffer[rbytes] = 0;
if(send(connfd, buffer, strlen(buffer), 0) < 0)
exit(-1);
}
if(close(connfd) < 0)
exit(-1);
}
close(listenfd);
return 0;
}
- Ta dluga lista
#include
ow to dolaczenie naglowkow systemowych / C. - Utworzylem sobie funkcje pomocnicza do drukowania zmiennej
errno
na stding, ze wzgledu na to, ze C nie drukuje zadnych informacji sam z siebie. - Deklaracje (czasami nawet definicje) zmiennych / stalych uzywanych w programie.
- Wywolanie funkcji
socket ()
, utworzenie giazda strumieniowego w domenie AF_INET. - Wyzerowanie, a nastepnie wypelnie gniazdowej struktury adresowej dla rodziny AF_INET:
[ port oraz adres IP musza byc wrzucone do struktury w network byte order ] - Otwarcie bierne, wywolywanie po kolei funkcji: bind(), listen(), accept(). Na tej ostatniej serwer usypia.
- Funkcja accept() powraca dajac deskryptor polaczonego klienta (albo blad), odbieramy od tego klienta wiadomosc, a nastepnie wysylamy echo tej wiadomosci. Odbieranie sie zazwyczaj realizuje w petli bo pakiety moga dojsc pofragmentowane.
- Pozamykanie gniazd (jak juz pisalem wczesniej, nie jest to konieczne, ale to dobra praktyka).
Jak widac, kod wyglada conajmniej nieciekawie. Jak chcesz to napisac w C++, to polecam zaczac od klasy (a moze nawet klas?) opakowujacych i zrobic z tego wersje user-friendly, zawsze to dobra zabawa, a i tak pisanie tego juz mi ponad pol godziny zajelo ;)
Teraz zajmiemy sie czyms w pythonie, mrr... :) Klient echa:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import socket
def main():
HOST = '127.0.0.1'
PORT = 9980
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockfd.connect((HOST, PORT))
sockfd.sendall('Wiadomosc echa')
data = sockfd.recv(1024)
print 'Received: ', repr(data)
sockfd.close()
if __name__ == '__main__':
main()
Tutaj to juz wyglada w miare w miare.
- Inicjalizacja zmiennych lokalny, tj. HOST, PORT.
- Utworzenie takiego samego gniazda jak w poprzednim przykladzie.
- Otwarcie aktywne, funkcja connect().
- Wyslanie, odebranie, oraz wydrukowanie odebranych danych
Tego by bylo chyba na tyle, wrzucam dodatkowo kod: klienta.c i server.py, ale juz na pastebin:
http://4programmers.net/Pastebin/2310
http://4programmers.net/Pastebin/2311
Dokumentacje na temat wywolan w jezyku C znajdziesz w podrecznikach systemowych man
, a natomiast dla pythona 2xx: http://docs.python.org/2/library/socket.html
Odnosnie gniazd, zachecam do zaglebienia sie w temacie (ksiazki Stevensa, Beejs guide)
Co do pipe
ow, to juz nie bede sie rozpisywac, bo mysle, ze nie trudno jest je ogarnac,
C: http://linux.die.net/man/2/pipe
Python: http://docs.python.org/2/library/pipes.html
Edit:
Istnieje jeszcze cos takiego jak gniazda w domenie UNIX (AF_UNIX), gdzie zamiast adresu, podajesz sciezke do gniazda. Komunikacja taka jest tylko lokalna, a na takiej Ci zalezy. Realizacja systemowa jej jest troszke uproszczona. Natomiast uzywa sie tego przez ten sam interfejs gniazdowy. Rowniez zachecam do poczytania ;)
Bardzo dziękuje za tak obszerną odpowiedź, szukałem informacji które pan wypisał w powyższym poście.
Komunikacja międzyprocesowa będzie stosunkowo wolna w porównaniu z:
a) DLL-ką (napisaną w jednym języku, wywołaną w innym)
b) modułami Pythona: zarówno w C jak i w Pascalu można zrobić moduł dla Pythona i wywoływać je wg potrzeb