Comunicación en Sistemas Operativos: Colas POSIX, TCP y UDP Sockets en C y Python
COLAS POSIX
Servidor
struct peticion { int op; char datos[256]; char cola_resp[64]; }; struct respuesta { int resultado; };
Mutex y variables globales
pthread_mutex_t mutex_mensaje; pthread_cond_t cond_mensaje; int mensaje_no_copiado = 1;
Función worker
void *tratar_mensaje(void *arg) { struct peticion *mes = (struct peticion *)arg; struct peticion mensaje_local;
Copiar mensaje
pthread_mutex_lock(&mutex_mensaje); memcpy(&mensaje_local, mes, sizeof(struct peticion)); mensaje_no_copiado = 0; pthread_cond_signal(&cond_mensaje); pthread_mutex_unlock(&mutex_mensaje);
Procesar
mqd_t q_cliente; struct respuesta resp; q_cliente = mq_open(mensaje_local.cola_resp, O_WRONLY); if (mensaje_local.op == 0) { resp.resultado = creat(mensaje_local.datos, mensaje_local.op); mq_send(q_cliente, (char *)&resp, sizeof(resp), 0); } else if (mensaje_local.op == 1) { resp.resultado = open(mensaje_local.datos, mensaje_local.op); mq_send(q_cliente, (char *)&resp, sizeof(resp), 0); } else if (mensaje_local.op == 2) { mq_send(q_cliente, (char *)&resp, sizeof(resp), 0); } else if (mensaje_local.op == 3) { resp.resultado = close(mensaje_local.op); mq_send(q_cliente, (char *)&resp, sizeof(resp), 0); } mq_close(q_cliente); pthread_exit(0); return NULL; }
Función main
int main(void) { mqd_t q_servidor; struct peticion mess; struct mq_attr attr; pthread_attr_t t_attr; pthread_t thid; attr.mq_maxmsg = 20; attr.mq_msgsize = sizeof(struct peticion);
Crear cola
q_servidor = mq_open("/COLA_SERVIDOR", O_CREAT | O_RDONLY, 0700, &attr); if (q_servidor == (mqd_t)-1) { perror("mq_open"); return 1; }
Inicialización de sincronización
pthread_mutex_init(&mutex_mensaje, NULL); pthread_cond_init(&cond_mensaje, NULL);
Configurar threads
pthread_attr_init(&t_attr); pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED);
Bucle infinito
while (1) { mq_receive(q_servidor, (char *)&mess, sizeof(mess), NULL); pthread_create(&thid, &t_attr, tratar_mensaje, &mess); pthread_mutex_lock(&mutex_mensaje); while (mensaje_no_copiado) pthread_cond_wait(&cond_mensaje, &mutex_mensaje); mensaje_no_copiado = 1; pthread_mutex_unlock(&mutex_mensaje); } return 0; }
Cliente
int abrir(char *name, int flags) { mqd_t q_servidor; mqd_t q_cliente; struct peticion pet; struct respuesta resp; struct mq_attr attr; char cola_nombre[64];
Crear cola
sprintf(cola_nombre, "/resp_%d", getpid()); attr.mq_maxmsg = 1; attr.mq_msgsize = sizeof(struct respuesta); q_cliente = mq_open(cola_nombre, O_CREAT | O_RDONLY, 0700, &attr);
Abrir cola servidor
q_servidor = mq_open("/COLA_SERVIDOR", O_WRONLY);
Preparar petición
pet.op = 1; strcpy(pet.cola_resp, cola_nombre); mq_send(q_servidor, (char *)&pet, sizeof(pet), 0); mq_receive(q_cliente, (char *)&resp, sizeof(resp), NULL); mq_close(q_servidor); mq_close(q_cliente); mq_unlink(cola_nombre); return (resp.resultado); }
TCP SOCKETS
Servidor
#define PUERTO 8080 #define MAX_CLIENTES 10
Función worker
void *atender_cliente(void *arg) { int cliente = *(int *)arg; free(arg); char buffer[256]; int n;
Recibir datos
n = recv(cliente, buffer, sizeof(buffer), 0); if (n > 0) { /* Procesar enunciado (operaciones, parsear...) */ send(cliente, "respuesta", strlen("respuesta"), 0); } close(cliente); pthread_exit(0); return NULL; }
Función main
int main() { int servidor, cliente; struct sockaddr_in servidor_addr, cliente_addr; socklen_t cliente_len; pthread_t tid; pthread_attr_t attr;
Crear socket
servidor = socket(AF_INET, SOCK_STREAM, 0); if (servidor < 0) { perror("socket"); return -1; }
Configurar dirección
memset(&servidor_addr, 0, sizeof(servidor_addr)); servidor_addr.sin_family = AF_INET; servidor_addr.sin_addr.s_addr = INADDR_ANY; servidor_addr.sin_port = htons(PUERTO);
Bind
if (bind(servidor, (struct sockaddr *)&servidor_addr, sizeof(servidor_addr)) < 0) { perror("bind"); return 1; }
Listen
if (listen(servidor, MAX_CLIENTES) < 0) { perror("listen"); return 1; }
Configurar threads
pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); printf("Servidor escuchando en el puerto %d ", PUERTO);
Bucle infinito
while (1) { cliente_len = sizeof(cliente_addr); cliente = accept(servidor, (struct sockaddr *)&cliente_addr, &cliente_len); if (cliente < 0) { perror("accept"); continue; } int *arg = malloc(sizeof(int)); *arg = cliente; pthread_create(&tid, &attr, atender_cliente, arg); } close(servidor); return 0; }
Cliente
#define PUERTO 8080 #define IP "127.0.0.1" #define TAM_BUFFER 256
int main() { int sock; struct sockaddr_in servidor_addr; char buffer[TAM_BUFFER];
Crear socket
sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return 1; }
Configurar dirección
memset(&servidor_addr, 0, sizeof(servidor_addr)); servidor_addr.sin_family = AF_INET; servidor_addr.sin_addr.s_addr = inet_addr(IP); servidor_addr.sin_port = htons(PUERTO);
Connect
if (connect(sock, (struct sockaddr *)&servidor_addr, sizeof(servidor_addr)) < 0) { perror("connect"); return 1; }
Enviar (protocolo enunciado)
send(sock, "datos", strlen("datos"), 0);
Recibir
int n = recv(sock, buffer, sizeof(buffer), 0); buffer[n] = '\0'; /* Cerrar */ close(sock); return 0; }
UDP SOCKETS
Servidor
int main() { int sock; struct sockaddr_in servidor_addr; struct sockaddr_in cliente_addr; socklen_t cliente_len; char buffer[256]; char respuesta[256];
Crear socket
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Configurar dirección
memset(&servidor_addr, 0, sizeof(servidor_addr)); servidor_addr.sin_family = AF_INET; servidor_addr.sin_addr.s_addr = INADDR_ANY; servidor_addr.sin_port = htons(9090); bind(sock, (struct sockaddr*)&servidor_addr, sizeof(servidor_addr));
Bucle
while (1) { cliente_len = sizeof(cliente_addr); int n = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&cliente_addr, &cliente_len); /* Procesar buffer según enunciado */ sendto(sock, respuesta, sizeof(respuesta), 0, (struct sockaddr*)&cliente_addr, cliente_len); } close(sock); return 0; }
Cliente
int main() { int sock; struct sockaddr_in servidor_addr; char buffer[256];
Crear socket
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Configurar dirección
memset(&servidor_addr, 0, sizeof(servidor_addr)); servidor_addr.sin_family = AF_INET; servidor_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); servidor_addr.sin_port = htons(9090); sendto(sock, "datos", strlen("datos"), 0, (struct sockaddr*)&servidor_addr, sizeof(servidor_addr));
Recibir
int n = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL); close(sock); return 0; }
PYTHON: CLIENTE CON SOCKETS Y THREADS
Código fuente
import socket import threading import os
REGISTER
def register(user, server_ip, server_port): try: sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sd.connect((server_ip, server_port)) sd.sendall("REGISTER\0".encode('utf-8')) sd.sendall((user + "\0").encode('utf-8')) res = sd.recv(1) if not res: sd.close() return 2 code = res[0] sd.close() return code except Exception: return 3
USERS
def users(user, server_ip, server_port): try: sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sd.connect((server_ip, server_port)) sd.sendall("USERS\0".encode('utf-8')) sd.sendall((user + "\0").encode('utf-8')) res = sd.recv(1) if not res: sd.close() return 2 code = res[0] if code == 0: Recibir número de usuarios num_str = "" while True: b = sd.recv(1) if not b or b == b'\0': break num_str += b.decode('utf-8') num_users = int(num_str) Recibir datos de cada usuario for i in range(num_users): user_data = "" while True: b = sd.recv(1) if not b or b == b'\0': break user_data += b.decode('utf-8') username, ip, port = user_data.split("::") print(f"Usuario: {username}, ip: {ip}, puerto: {port}") sd.close() return code except Exception: return 3
SEND
def send(user, ip, port, target, msg): try: sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sd.connect((server_ip, server_port)) sd.sendall("SEND\0".encode('utf-8')) sd.sendall((user + "\0").encode('utf-8')) if code == 0: msg_id = "" while True: b = sd.recv(1) if not b or b == b'\0': break msg_id += b.decode('utf-8') print(f"SEND OK - MENSAJE {msg_id}") sd.close() return code except Exception: return 3
CONNECT
@staticmethod def connect(user): if len(user) > MAX_USERNAME_LENGTH: print("c> CONNECT FAIL") return client.RC.ERROR sock = None try: Buscar puerto libre sock_temporal = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_temporal.bind(("", 0)) listen_port = sock_temporal.getsockname()[1] sock_temporal.close() Conectar al servidor sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((client._server, client._port)) sock.sendall(b'CONNECT\0') sock.sendall(user.encode() + b'\0') sock.sendall(str(listen_port).encode() + b'\0') respuesta = sock.recv(1)[0] if respuesta == 0: client._listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client._listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) client._listen_socket.bind(('0.0.0.0', listen_port)) client._listen_socket.listen() client._file_server_running = True client._listen_thread = threading.Thread( target=client._file_server_thread, daemon=True ) client._listen_thread.start() client._connected_user = user print("c> CONNECT OK") return client.RC.OK elif respuesta == 1: print("c> CONNECT FAIL. USER DOES NOT EXIST") return client.RC.USER_ERROR elif respuesta == 2: print("c> CONNECT FAIL. USER ALREADY CONNECTED") return client.RC.USER_ERROR else: print("c> CONNECT FAIL") return client.RC.ERROR except Exception: print("c> CONNECT FAIL") return client.RC.ERROR finally: if sock: sock.close()
GET-FILE
@staticmethod def getfile(user, remote_fileName, local_fileName): Obtener IP y puerto del usuario remoto de la lista local (se asume que existe) ip, port = lista_users[user]["ip"], int(lista_users[user]["port"]) sock = None file_received = False try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) Enviar petición sock.sendall(b'GET-FILE\0' + remote_fileName.encode() + b'\0') Recibir respuesta respuesta = sock.recv(1)[0] if respuesta == 0: Recibir tamaño file_size = int(client.readString(sock)) Recibir contenido en bloques with open(local_fileName, 'wb') as f: remaining = file_size while remaining > 0: data = sock.recv(min(remaining, 4096)) if not data: raise Exception f.write(data) remaining -= len(data) file_received = True print("c> GET-FILE OK") return client.RC.OK elif respuesta == 1: print("c> GET-FILE FAIL, FILE DOES NOT EXIST") return client.RC.USER_ERROR else: print("c> GET-FILE ERROR") return client.RC.ERROR except Exception: print("c> GET-FILE ERROR") return client.RC.ERROR finally: if not file_received and os.path.exists(local_fileName): os.remove(local_fileName) if sock: sock.close()