Instalación de OmniORB sobre Ubuntu 14.04

OmniORB es un Object Request Broker (ORB) que implementa la especificación 2.6 de la Common Object Request Broker Architecture (arquitectura común de intermediarios en peticiones a objetos), más conocida como CORBA.

Ha sido diseñado para ser portable. Corre en muchos tipos de sistemas UNIX, Windows, varios sistemas operativos embebidos, y sistemas relativamente desconocidos como OpenVMS o Fujitsu-Siemens BS2000. Ha sido diseñado para ser fácil de portar a nuevas plataformas. El mapeo de IDL a C++ es el mismo para todas las plataformas.

OmniORB usa excepciones y clases anidadas de C++. Mantiene en lo posible la especificación estándar de CORBA y no usa mapeos alternativos para C++. Se basa en librerías nativas de hilos que proporcionan capacidad multihilo. Además, también está disponible para Python.

Para llevar a cabo la instalación de OmniORB (Free CORBA ORB) sobre Ubuntu 14.10, es necesario realizar los siguientes pasos:

  • Descargar OmniORB 4.1.5
  • Descomprimir. Para ello, escribimos en terminal:
    tar xzf omniORB-4.X.X.tar.gz 
    cd omniORB-4.X.X
  • Configure:
    ./configure --prefix=/opt --enable-threads --enable-shared
  • Compilar
    make
  • Instalar
    make install

Se pueden configurar algunas opciones en el momento de la instalación mediante el uso de
algunos flags:

    • –disable-static: Compilación rápida. Algunas librerías estáticas son producidas.
    • –enable-threads: Usa pthreads
    • –enable-shared: default – shared libraries generadas

Más información en The omniORB version 4.1 User’s Guide.

Instalar y configurar ProFTPD en Ubuntu 14.04

Recientemente he necesitado instalar y configurar un servicio de FTP (File Transfer Protocol) sobre Ubuntu 14.04 Natty Narwhal. Para este propósito, he elegido ProFTPd. ProFTPd es un servidor FTP bajo licencia GPL y multiplataforma. Puede configurarse de una manera rápida y fácil. Además, soporta IPv6.Estos son los pasos a seguir para su instalación y configuración:

sudo apt-get install proftpd

A continuación se puede seleccionar «INETD» o «Independiente». Seleccionar «Independiente». Después, abrir el fichero /etc/proftpd/proftpd.conf y descomentar la línea DefaultRoot ~ , quedando como sigue:

# Use this to jail all users in their homes
DefaultRoot ~

Reiniciar el servicio, con sudo /etc/init.d/proftpd restart. Ahora ya puedes acceder por FTP a tu directorio HOME.

Opcionalmente, podemos crear un nuevo usuario:

sudo mkdir /home/usuarioftp

Lo añadimos al sistema

sudo useradd -d /home/usuarioftp -s /bin/false usuarioftp

y le asignamos una carpeta:

sudo chown -R usuarioftp /home/usuarioftp

Antes de proceder a establecer los permisos, necesitamos especificar contraseña del usuario:

sudo passwd usuarioftp

Ahora, añadimos al final del fichero proftpd.conf el siguiente bloque para limitar el acceso por FTP solo permitiendo el usuario que hemos creado:

AllowUser usuarioftp
DenyAll
 
RequireValidShell off

Y para terminar reiniciamos el servicio de ProFTPd para aplicar los cambios:

/etc/init.d/proftpd restart

Chat multihilo con Sockets en Python y en C

La computación concurrente es la capacidad de simultanear en la ejecución de múltiples tareas interactivas. Un proceso es un programa en ejecución, que es gestionado por el Sistema Operativo y compite por los recursos del procesador. Los procesos tienen estado y memoria en ejecución reservada. El mecanismo por el cual un proceso crea otro proceso se denomina bifurcación (fork). Cuando un proceso se bifurca, se crea una copia exacta del proceso en ejecución, independiente del resto y no comparte el espacio de memoria con el proceso que los ha creado ni con otros procesos.

Un hilo, en sistemas operativos, es una característica que permite a una aplicación realizar varias tareas a la vez (concurrentemente). Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, o los archivos abiertos. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente. Un hilo es un tarea que se ejecuta en paralelo con otra tarea.

La comunicación entre el cliente y el servidor se hace posible gracias a estructuras abstractas denominadas sockets, mediante las cuales los programas pueden intercambiar flujo de datos e información. Este concepto está asociado al concepto de puerto.

Un puerto es una forma genérica de denominar a una interfaz a través de la cual los diferentes tipos de datos se pueden enviar y recibir. En el protocolo TCP/IP, son de tipo lógico, por ejemplo, los puertos que permiten la transmisión de datos entre diferentes computadores.

Existen dos tipos de sockets, orientados a conexión y no orientados a conexión. La diferencia fundamental es que en los sockets orientados a conexión (TCP) el protocolo garantiza que los datos serán entregados en su destino sin errores y en el mismo orden en que se transmitieron, mientras que en los sockets no orientados a conexión (o UDP) no se garantiza que el mensaje llegue a su destino. Parece claro que si el programa envía un mensaje y no hay nadie escuchando, ese mensaje se pierde. De todas formas, aunque haya alguien escuchando, el protocolo tampoco garantiza que el mensaje llegue. Lo único que garantiza es, que si llega, llega sin errores.

En una comunicación con sockets multihilo, como es el caso de la implementación que nos ocupa, cada conexión es gestionada por un proceso o hilo de ejecución independiente. Así, con cada cliente que conecte con el servidor, se expande un nuevo hilo del lado del servidor, que gestionará las peticiones del cliente asociado a él. Servidores concurrentes pueden ser multiproceso o multihilo. Estos son utilizados para servicios largos con mucha sincronización Cliente-Servidor.

A continuación dejo el código de ambas implementaciones, primero en C++ y después en Python.

Comandos

  • ADD usuario:Introduce un usuario en el chat.
  • LIST: Obtiene la lista de clientes conectados.
  • END: Desconecta y sale de la sesión.
  • TEXT: Envía un mensaje a todos los usuarios conectados.
  • TEXT TO usuario: Envía un mensaje privado a un usuario.

En C++

Servidor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
 
#define SERVER_PORT	6543
#define SERVER_ADDRESS	"127.0.0.1"
#define MAXLINE		512
#define MAXCLIENTS	10
 
int buscarCliente(char*);
void subCadena(char*, char*, int, int);
 
struct vector
{
	int socket;
	char usuario[MAXLINE-4];
	int sign_in;
};
 
struct vector vectorClientes[MAXCLIENTS];
int clientes = 0;
 
int main(int argc, char *argv[])
{
    void* gestionaCliente(void* p);
 
    int socketfd, new_sd;
    socklen_t client_len;
    struct sockaddr_in server_addr, client_addr;
    int i, status, id;
    pthread_t hilos[MAXCLIENTS];
 
    for(i=0;i<MAXCLIENTS;i++)
	strcpy(vectorClientes[i].usuario, " ");
 
    // Open TCP internet STREAM socket
    if ((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	perror("server: Can't open stream socket");
 
    // Bind local address to allow the client to connect
    bzero((char *) &server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);
    if (bind
	(socketfd, (struct sockaddr *) &server_addr,
	 sizeof(server_addr)) < 0)
	perror("server: can't bind local address");
    listen(socketfd, 5);
 
    for (;;) {
	client_len = sizeof(client_addr);
	if((new_sd = accept(socketfd, (struct sockaddr *) &client_addr, &client_len)) < 0) {
		printf("Error aceptando peticiones\n");
		exit(0);
	}	
	else {	
		id = clientes;		
		vectorClientes[id].socket = new_sd;
		vectorClientes[id].sign_in = 0;		
		fflush(stdout);			
		clientes++;
		if ( (status = pthread_create(&hilos[id],NULL,gestionaCliente,(void *)&id)) )
		{
			printf("Error al crear el hilo\n");
			exit(0);
		}
	}
   }
   close(socketfd);	// Close original socket
   return 0;
}
 
void subCadena(char *subCad, char *cad, int inicio, int cuantos)
{
     int i,j=0;
     for(i=inicio;i<inicio+cuantos && cad[i]!='\0';i++)
     {
        subCad[j]=cad[i];
        j++;
     }
     subCad[j]='\0';
}
 
int buscarCliente(char* usuario)
{
	int i;
	for(i=0;i<clientes;i++)
	{
		if(strcmp(vectorClientes[i].usuario,usuario ) == 0 && vectorClientes[i].sign_in == 1)
		return vectorClientes[i].socket;
	}
	return -1;
}
 
void* gestionaCliente(void* p)
{
	int *ide, id;
	ide = (int* ) p;
	id = *ide;
	char buffer[MAXLINE], nombre[MAXLINE-4], temp[MAXLINE-8];
	int i, longitud, destino;
 
	while(1)
	{
	recv(vectorClientes[id].socket,buffer,MAXLINE,0);
	printf("\nid%d\n", id);
 
	if(strstr(buffer, "ADD") && vectorClientes[id].sign_in == 0) {
		longitud = strlen(buffer);
		//Le quitamos el ADD
		subCadena(nombre, buffer, 4, longitud-4);
		strcpy(vectorClientes[id].usuario, nombre);
		//Se informa a todos menos a él mismo y al que se haya ido
		strcpy(buffer, "El usuario ");
		strcat(buffer, nombre);
		strcat(buffer, " ha entrado en el chat.");
		for(i = 0; i < clientes; i++)
			if (i != id && vectorClientes[i].sign_in == 1)
			send(vectorClientes[i].socket,buffer,MAXLINE,0);
		vectorClientes[id].sign_in = 1;
		}
	if(strstr(buffer, "LIST") && vectorClientes[id].sign_in == 1) {
		//Se envia al cliente todos los usuarios menos los que hayan abandonado la sesión
		for(i = 0; i < clientes; i++){
			if(vectorClientes[i].sign_in == 1)
				send(vectorClientes[id].socket, vectorClientes[i].usuario, MAXLINE, 0);			
			}		
		}
	if(strstr(buffer, "END") && vectorClientes[id].sign_in == 1) {
		//Se informa a todos menos a él mismo y al que se haya ido
		strcpy(buffer, "El usuario ");
		strcat(buffer, vectorClientes[id].usuario);
		strcat(buffer, " ha abandonado en el chat.");
		bzero(vectorClientes[id].usuario, MAXLINE);
		for(i = 0; i < clientes; i++)
			if (i != id && vectorClientes[i].sign_in == 1)
				send(vectorClientes[i].socket,buffer,MAXLINE,0);
		vectorClientes[id].sign_in = 0;
		}
	if(strstr(buffer, "TEXT") && !strstr(buffer, "TEXT TO") && vectorClientes[id].sign_in == 1) {
		longitud = strlen(buffer);
		subCadena(temp, buffer, 5, longitud-5);
		//Se envía a todos menos a él mismo y al que se haya ido
		bzero(buffer, MAXLINE);
		strcat(buffer, vectorClientes[id].usuario);
		strcat(buffer, " dice: ");
		strcat(buffer, temp);
		for(i = 0; i < clientes; i++)
			if (i != id && vectorClientes[i].sign_in == 1)
			send(vectorClientes[i].socket,buffer,MAXLINE,0);
		}
	if(strstr(buffer, "TEXT TO") && vectorClientes[id].sign_in == 1) {
		//Le quitamos el TEXT TO
		subCadena(nombre, buffer, 8, MAXLINE-8);
		//Nos quedamos sólo con el nombre, quitando desde el primer espacio en blanco hasta el final
		strtok(nombre," ");
		//Se obtiene el socket destino
		destino = buscarCliente(nombre);
		longitud=strlen(nombre);
		strcpy(nombre, vectorClientes[id].usuario);		
		strcat(nombre, " dice: ");
		//Recortamos el TEXT TO, el nombre, y los dos espacios hasta el mensaje(se suma solo uno (un espacio) 
		//porque empieza a recorrer longitud(instruccion)+longitud(nombre) desde la pos. 0 de la cadena.		
		subCadena(temp, buffer, 8+longitud+1, MAXLINE-(8+longitud+1));
		strcat(nombre, temp);
		if(destino != -1)
			send(destino, nombre, MAXLINE, 0);
		}
	fflush(stdout);
	}
	close(vectorClientes[id].socket);
}
Cliente
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
 
#define SERVER_PORT	6543
#define SERVER_ADDRESS	"127.0.0.1"
#define MAXLINE		512
 
void* recibir(void* p);
void* enviar(void* p);
 
int main()
{
	struct sockaddr_in addr;
	int sd,status;
	pthread_t hilos[2];
 
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
	addr.sin_port = htons(SERVER_PORT);
 
	if((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("Error al crear el socket\n");
		exit(0);	
	}	
	if(connect(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		printf("Error al conectar\n");
		exit(0);
	}
	else
	{	
		if ( (status = pthread_create(&hilos[0],NULL,recibir,(void*)&sd)) )
		{
			printf("Error al crear hilo para recibir\n");
			close(sd);
			exit(0);
		}		
		if ( (status = pthread_create(&hilos[1],NULL,enviar,(void*)&sd)) )
		{
			printf("Error al crear hilo para enviar\n");
			close(sd);
			exit(0);
		}
		pthread_join(hilos[0],NULL);
		pthread_join(hilos[1],NULL);		
	}
	return 1;
}
 
void* recibir(void* p)
{
	int* id;
	char buffer[MAXLINE];
	id = (int*) p;
	while(1)
	{
		recv(*id,buffer,MAXLINE,0);
		printf("%s\n",buffer);
		fflush(stdout);
	}
}
 
void* enviar(void* p)
{
	int* id;
	char buffer[MAXLINE];
	id = (int*) p;
	while(1)
	{	 
		printf("\tIntroduce el mensaje\n-> ");
		fgets(buffer , MAXLINE , stdin);
		strtok(buffer,"\n");
		send(*id,buffer,MAXLINE,0);
		sleep(3);
	}
}

chat-en-c-2

En Python

Servidor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Servidor
 
import string
import threading
import socket
 
clientes = {'nombre':[], 'socket':[]}
 
class gestionaClientes(threading.Thread):
 
    def __init__(self, socket):
        threading.Thread.__init__(self)
	self.conn = socket
	self.conectado = False
	self.data = ''
    def run(self):
	while True:
		self.data = self.conn.recv( 1024 )
 
		if 'ADD' in self.data:
			#Busca si ya ha sido insertado
			if(self.conectado == False):
				self.conectado = True					
				clientes['nombre'].append(self.data[4:])
				clientes['socket'].append(self.conn)
				for i in clientes['socket']:
					if i != self.conn:
						i.send(self.data[4:]+" ha entrado en el chat.")
			else:
				self.conn.send("Ya estás en el chat.")
			print clientes
 
		if ('LIST' in self.data) and (self.conectado == True):
			for i in clientes['nombre']:
					print "enviado a "+str(self.conn)+" "+str(i)
					self.conn.send(i+" ")
			print clientes
 
		if ('END' in self.data):
			if (self.conectado == True):
				for i in clientes['socket']:
					if i == self.conn:
						nombre = clientes['nombre'][clientes['socket'].index(i)]
						clientes['nombre'].remove(nombre)
						clientes['socket'].remove(i)
						self.conectado = False
				for i in clientes['socket']:
					if i != self.conn:		
						i.send(nombre+" ha salido del chat.")
				self.conn.send(" ")
			else:
				self.conn.send(" ")
		if ('TEXT' in self.data and 'TEXT TO' not in self.data) and (self.conectado == True):
			for i in clientes['socket']:
				if i != self.conn:
					i.send(clientes['nombre'][clientes['socket'].index(self.conn)]+" dice: "+self.data[5:])
			print clientes
 
		if ('TEXT TO' in self.data) and (self.conectado == True):
			palabras = self.data[8:].split()
			#busca si existe alguien con ese alias
			for i in clientes['nombre']:
				if i == palabras[0]:
					#Prepara el mensaje
					del palabras[0]
					mensaje = string.join(palabras, ' ')
					clientes['socket'][clientes['nombre'].index(i)].send(clientes['nombre'][clientes['socket'].index(self.conn)]+" dice: "+mensaje)
 
 
	self.conn.close() 
 
#creamos socket pasivo y escuchamos en el puerto 9000
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.bind( ( socket.gethostname(), 9000 ) )
s.listen( 5 )
while(True):
	conn, addr = s.accept()
	gestionaClientes(conn).start()
Cliente
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Cliente
 
from Tkinter import *
import threading
import socket
 
class App:
 
    def __init__(self, master, socket):
 
	self.conn = socket
 
        self.frame = Frame(master)
	self.label = Label(self.frame, text="Cliente chat. Python+TkInter. David López")
 
	self.textarea = Text(self.frame, height=20, width=40)
	self.scroll = Scrollbar(self.frame, command=self.textarea.yview)
	self.textarea.configure(yscrollcommand=self.scroll.set)
 
	self.texto_enviar = StringVar()
	self.text_ent = Entry(self.frame, textvariable=self.texto_enviar)
 
        self.btn_enviar = Button(self.frame, text="Enviar", command=self.enviar)
        self.btn_salir = Button(self.frame, text="Salir", command=self.salir)
 
	self.frame.grid()
	self.label.grid(row=0, column=0, columnspan=3)
	self.textarea.grid(row=1, column=0, columnspan=2)
	self.scroll.grid(row=1, column=2, sticky=N+S)
	self.text_ent.grid(row=2, column=0, columnspan=2, sticky=W+E)
	self.btn_enviar.grid(row=3, column=0)
	self.btn_salir.grid(row=3, column=1)
 
    def enviar(self):
	self.conn.send(self.text_ent.get())
	self.text_ent.delete(0, END)
 
    # Esta es una función de retrollamada.
    def salir(self):
	lee.parar()
	self.conn.send("END")
	self.frame.quit()
 
    def escribir(self, texto):
	self.textarea.insert(END, texto)
 
class leer(threading.Thread):
    def __init__(self, socket):
        threading.Thread.__init__(self)
	self.mensaje = ''
	self.conn = socket
	self.stop = False
    def run(self):
	while (self.stop == False):
		self.mensaje = self.conn.recv( 1024 )
		app.escribir(self.mensaje+'\n')
	self.conn.close()
    def parar(self):
	self.stop = True
 
miSocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
miSocket.connect( (socket.gethostname(), 9000 ) )
 
lee = leer(miSocket)
 
lee.start()
 
root = Tk()
root.title('Chat Python-TkInter - David López')
app = App(root, miSocket)
 
root.mainloop()

 

 

chatgrafico