Você está na página 1de 38

Comunicação entre Processos

•Canal de comunicação
•Arquitectura da comunicação
•Modelos de comunicação

Sistemas Operativos
1
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Comunicação entre Processos


IPC – Inter Process Communication
• Para interactuarem os processos necessitam de
se sincronizar e de trocar dados
– generalização do modelo de interacção entre processos em
que para além da sincronização existe transferência de
informação
– a transferência de informação é suportada por um canal de
comunicação disponibilizado pelo sistema operativo
• Protocolo e estrutura das mensagens
– Os processos que comunicam necessitam de estabelecer a
estrutura das mensagens trocadas, bem como o protocolo que
rege a troca das mesmas
– Normalmente o sistema operativo considera as mensagens
como simples sequências de octetos

Sistemas Operativos
2
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 1
Comunicação entre Processos

Processo Processo
Produtor Mensagem
Consumidor
Enviar Receber

Canal de Comunicação

• generalização do modelo de interacção entre os


processos
Sistemas Operativos
3
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Canal de Comunicação

• Na definição da arquitectura de comunicação é


fundamental ter presente:
– como são transferidos os dados entre os espaços de
endereçamento dos processos
– qual a sincronização associada
• O canal de comunicação pode ser implementado
com dois tipos de mecanismos:
– memória partilhada: os processos acedem a uma zona de
memória que faz parte do espaço de endereçamento dos
processos comunicantes
– o canal é implementado pelo núcleo do sistema operativo; os
dados são sempre copiados para o núcleo antes de serem
transferidos

Sistemas Operativos
4
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 2
Arquitectura da Comunicação:
memória partilhada

Espaço de endereçamento
do processo P2

Zona de memória partilhada por P1 e P2


Espaço de
Endereçamento

Espaço de endereçamento
do processo P1

Sistemas Operativos
5
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Arquitectura da Comunicação:
cópia através do núcleo

Variável com a Espaço de endereçamento


mensagem do produtor

Variável que recebe


a mensagem Espaço de endereçamento
do consumidor

Buffer no núcleo Espaço de endereçamento


do núcleo

Sistemas Operativos
6
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 3
Memória Partilhada

• Apont = CriarRegião (Nome, Tamanho)


• Apont = AssociarRegião (Nome)
• EliminarRegião (Nome)

São necessários mecanismos de sincronização adicionais


para:
– Garantir exclusão mútua sobre a zona partilhada
– Sincronizar a actividade dos processos produtor e consumidor (ex.
produtor-consumidor ou leitores-escritores)

Sistemas Operativos
7
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Objecto de Comunicação do
Sistema
• IdCanal = CriarCanal(Nome)
• IdCanal = AssociarCanal (Nome)
• EliminarCanal (IdCanal)
• Enviar (IdCanal, Mensagem)
• Receber (IdCanal, Mensagem)

Não são necessários mecanismos de sincronização


adicionais porque são implementados pelo núcleo do
Sistema Operativo
Sistemas Operativos
8
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 4
Comparação: memória partilhada
vs. cópia através do núcleo

• Memória partilhada: • Objecto de


– mecanismo mais Comunicação do
eficiente Sistema:
– a sincronização tem de – velocidade de transferência
ser explicitamente limitada pelas duas cópias
programada da informação e pelo uso
– programação complexa das chamadas sistema para
Enviar e Receber
– sincronização implícita
– fácil de utilizar

Sistemas Operativos
9
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Resumo do Modelo
Computacional
• memória partilhada:
– Endereço = CriarRegião ( Nome, Dimensão )
– Endereço = AssociarRegião ( Nome )
– EliminarRegião ( Endereço )
• caixas do correio:
– IdCC = CriarCCorreio ( Nome, Parâmetros )
– IdCC = AssociarCCorreio ( Nome )
– EliminarCCorreio ( IdCC )
• ligações virtuais (para suporte ao diálogo):
– IdCanalServidor = CriarCanal ( Nome )
– IdCanal = EsperarLigação ( IdCanalServidor )
– IdCanal = PedirLigação ( Nome )

Sistemas Operativos
10
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 5
Unix– Modelo Computacional - IPC
• pipes
• sockets
• memória partilhada

Bibliografia:
• Unix Network Programming (Caps. 3 e 6)
• Fundamentos de Sistemas Operativos
Sistemas Operativos
11
Comunicação JAM, PJG, PF, CNR, JCCC, RR

PIPES

Sistemas Operativos
12
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 6
Sistema de Ficheiros

• Sistema de ficheiros hierarquizado


• Tipos de ficheiros:
– Normais – sequência de octetos (bytes) sem uma organização em
registos (records)
– Ficheiros especiais – periféricos de E/S, pipes, sockets
– Ficheiros directório
• Quando um processo se começa a executar o sistema abre
três ficheiros especiais
– stdin – input para o processo (fd – 0)
– stdout – Output para o processo (fd – 1)
– stderr – periférico para assinalar os erros (fd – 2)
• Um file descriptor é um inteiro usado para identificar um
ficheiro aberto ( os valores variam de zero até máximo
dependente do sistema)

Sistemas Operativos
13
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Sistema de Ficheiros
main (argc, argv)
int argc;
char *argv[];
{
int origem, destino, n;
char buffer[1024];

origem = open (argv[1], O_RDONLY);


if (origem == -1) {
printf ("Nao consigo abrir %s \n",argv[1]);
exit(1);
}
destino = creat (argv[2], 0666);
if (destino == -1) {
printf ("Nao consigo criar %s \n", argv[2]);
exit(1);
}
while ((n = read (origem, buffer, sizeof(buffer))) > 0)
write (destino, buffer, n);
exit(0);
Sistemas Operativos
} 14
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 7
Sistema de Ficheiros UNIX
Process

program program
FILE* iobuf FILE* iobuf
stdio stdio
flush flush

open/read/write/close open/read/write/close
USER FILE DESCRIPTOR TABLE USER FILE DESCRIPTOR TABLE

FILE TABLE Kernel

Inode TABLE

CACHE
sync
DISCO

Sistemas Operativos
15
Comunicação JAM, PJG, PF, CNR, JCCC, RR

IPC no UNIX

• Mecanismo inicial:
– pipes
• Extensão dos pipes:
– pipes com nome
• Evolução do Unix BSD 4.2:
– sockets

Bibliografia:
•Unix Network Programming (Caps. 3 e 6)
Sistemas Operativos
•Fundamentos de Sistemas Operativos
16
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 8
Pipes

• Mecanismo original do Unix para para comunicação entre


processos.
• Têm uma interface idêntica à dos ficheiros
• Constitui um dos conceitos unificadores na estrutura do
interpretador de comandos
• Canal (byte stream) ligando dois processos
• Permite um fluxo de informação unidireccional, um processo
escreve num pipe e o correspondente lê na outra extremidade
• Não tem nome lógico associado
• As mensagens são sequências de octetos de qualquer dimensão
processo pai processo filho
write fd read fd

sistema operativo

Sistemas Operativos pipe 17


Comunicação JAM, PJG, PF, CNR, JCCC, RR

Pipes

int pipe (int *fds);

• fds[0] – descritor aberto para leitura


• fds[1] – descritor aberto para escrita

• Os descritores de um pipe são análogos ao dos ficheiros


• As operações de read e write sobre ficheiros são válidas
para os pipes
• Os descritores são locais a um processo podem ser
transmitidos para os processos filhos através do
mecanismo de herança
• O processo fica bloqueado quando escreve num pipe cheio
• O processo fica bloqueado quando lê de um pipe vazio
Sistemas Operativos
18
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 9
Pipes

char msg[] = “utilizacao de pipes”;

main() {
char tampao[1024];
int fds[2];

pipe(fds);

for (;;) {
write (fds[1], msg, sizeof (msg));
read (fds[0], tampao, sizeof (msg)));
}
}

Sistemas Operativos
19
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Pipes

Processo Utilizador

read fds

write fds

pipe

Sistemas Operativos
20
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 10
Comunicação pai-filho
#include <stdio.h> }
#include <fnctl.h> else {
#define TAMSG 100 /* processo pai */
char msg[] = “mensagem de teste”; /* escreve no pipe */
char tmp[TAMSG]; write (fds[1], msg,
sizeof (msg));
pid_filho = wait();
main() {
}
int fds[2], pid_filho;
}
if (pipe (fds) < 0) exit(-1);
if (fork () == 0) {
/* lê do pipe */
read (fds[0], tmp, sizeof (msg));
printf (“%s\n”, tmp);
exit (0);

Sistemas Operativos
21
Comunicação JAM, PJG, PF, CNR, JCCC, RR

DUP – System Call


• dup (fd1) cria uma cópia de fd1 e coloca essa cópia no menor
descritor disponível

Antes Depois

fd1 Livre kernel fd1 kernel


file file
information information

fd2 fd2

Sistemas Operativos
22
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 11
DUP – System Call
• dup2(fd1, fd2) faz de fd2 uma cópia de fd1, fechando fd2 se
necessário

Antes Depois

fd1 kernel fd1 kernel


file file
information information

fd2 kernel fd2


file
information
Sistemas Operativos
23
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Redireccionamento de
Entradas/Saídas
#include <stdio.h> /* fecha os descritores não usados pelo
#include <fnctl.h> filho */
#define TAMSG 100 close (fds[0]);
char msg[] = “mensagem de teste”; close (fds[1]);
char tmp[TAMSG];
/* lê do pipe */
read (0, tmp, sizeof (msg));
main() {
printf (“%s\n”, tmp);
int fds[2], pid_filho;
exit (0);
if (pipe (fds) < 0) exit(-1); }
if (fork () == 0) { else {
/* processo filho */ /* processo pai */
/* liberta o stdin (posição zero) */ /* escreve no pipe */
close (0); write (fds[1], msg, sizeof (msg));
pid_filho = wait();
/* redirecciona o stdin para o pipe }
de leitura */
}
dup (fds[0]);

Sistemas Operativos
24
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 12
Redireccionamento de
Entradas/Saídas (cont.)
pai filho

stdin stdin
stdout stdout close (0)
dup (fds[0]);
close (1); stderr stderr close (fds[0]);
dup (fds[1]); close (fds[1]);
close (fds[0]); fds[0] fds[0]
read (0, ...);
close (fds[1]);
fds[1] fds[1]
write (1, ...);

[1] pipe [0]

Sistemas Operativos
25
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Redireccionamento de
Entradas/Saídas (cont.)

exemplo:
who | sort | lpr

processo who processo sort processo lpr


write fd read fd read fd

write fd

sistema operativo

pipe 1 pipe 2

Sistemas Operativos
26
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 13
popen

• A forma mais simples de criar um pipe


• Semelhante a um fopen, excepto que retorna um pipe via um
FILE *

ptr = popen("/usr/bin/ls", "r");

• Para fechar o pipe: pclose(FILE *);

Sistemas Operativos
27
Comunicação JAM, PJG, PF, CNR, JCCC, RR

popen (cont.)
EXEMPLO: Escrever no standard output a lista de
ficheiros *.c

#include <stdio.h>
#include <stdlib.h>
main() {
char *cmd = "/usr/bin/ls *.c";
char buf[BUFSIZ];
FILE *ptr;

if ((ptr = popen(cmd, "r")) != NULL)


while (fgets(buf, BUFSIZ, ptr) != NULL)
printf("%s", buf);
return 0;
}
Sistemas Operativos
28
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 14
popen (cont.)
pai filho pai filho
#include <stdio.h>

stdin stdin stdin stdin


#define READ 0
#define WRITE 1 stdout stdout stdout stdout
#define tst (a,b) (mode == READ ? (b) : (a))
stderr stderr stderr stderr
static int popen_pid;
p[0] p[0] p[0] p[0]
Int popen (char* cmd, int mode) {
int p[2]; p[1] p[1] p[1] p[1]
if (pipe(p) < 0) return (NULL);

mode = READ mode =WRITE


if ((popen_pid = fork()) == 0) }
close ( tst (p[WRITE], p[READ])); ----------------- close ( p[0]); ------------------------ close (p[1]); o filho lê o que
close ( tst (0, 1)); ----------------------------------------- close (1); ------------------------------ close (0); o pai envia
dup ( tst (p[READ], p[WRITE])); ------------------- dup (p[1]); --------------------------- dup (p[0]); ----------
close ( tst (p[READ], p[WRITE])); ------------------ close (p[1]); -------------------------- close (p[0]);
execl (“/bin/sh”, “sh”, “-c”, cmd, 0);
exit (1);
}
if (popen_pid == -1) return (NULL); o pai envia
close ( tst (p[READ], p[WRITE])); --------------------- close (p[1]); ---------------------------- close (p[0]); para o filho
return ( tst (p[WRITE], p[READ])); ------------------ return (p[0]); ------------------------- return (p[1]); -------
}
os argumentos
Sistemas Operativos
do comando
29
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Pipes com Nome


(Named Pipes ou FIFO)
• Para dois processos (que não sejam pai e filho)
comunicarem é preciso que o pipe seja identificado por
um nome
• Atribui-se um nome lógico ao pipe
• O espaço de nomes usado é o do sistema de ficheiros
• Um named pipe comporta-se como um ficheiro,
existindo uma entrada na directoria correspondente
• Um named pipe pode ser aberto por processos que não
têm qualquer relação hierárquica

Sistemas Operativos
31
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 15
Pipes com Nome

• um named pipe é um canal :


– unidireccional
– interface sequência de caracteres (byte stream)
– um processo associa-se com a função open
– é eliminado com a função unlink
– o envio de informação é efectuado com a função write
– a leitura da informação é efectuada com a função read
• A função mknod ou mkfifo permite criar ficheiros com
características especiais e serve para criação dos
named pipes.
int mkfifo (char *pathname, int mode)

Sistemas Operativos
32
Comunicação JAM, PJG, PF, CNR, JCCC, RR

/* Servidor */
/* Cliente */
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#define TAMMSG 1000 #define TAMMSG 1000

void produzMsg (char *buf) { main () {


strcpy (buf, “Mensagem de teste”); int fcli, fserv, n;
} char buf[TAMMSG];
void trataMsg (buf) {
printf (“Recebeu: %s\n”, buf); unlink("/tmp/servidor");
} unlink("/tmp/cliente");

main() { if (mkfifo("/tmp/servidor", 0777) < 0) exit(-1)


int fcli, fserv; if (mkfifo("/tmp/cliente", 0777) < 0) exit(-1);
char buf[TAMMSG];
if((fserv=open("/tmp/servidor",O_WRONLY))<0) if ((fserv = open("/tmp/servidor",O_RDONLY))< 0
exit (-1);
exit (-1);
if ((fcli = open ("/tmp/cliente",O_WRONLY)) < 0
if((fcli=open("/tmp/cliente",O_RDONLY))<0)
exit (-1);
exit (-1);
produzMsg (buf); for (;;) {
write (fserv, buf, TAMMSG); n = read (fserv, buf, TAMMSG);
read (fcli, buf, TAMMSG); if (n <= 0) break;
trataPedido (buf);
trataMsg (buf);
n = write (fcli, buf, TAMMSG);
close (fserv); close (fcli); }
} close (fserv); close (fcli);
Sistemas Operativos unlink("/tmp/servidor"); unlink("/tmp/cliente")
33
Comunicação JAM, PJG, PF, CNR,
} JCCC, RR

Page 16
Sockets

• Interface de programação para comunicação


entre processos introduzida no Unix 4.2 BSD
• Objectivos:
– independente dos protocolos
– transparente em relação à localização dos processos
– compatível com o modelo de E/S do Unix
– eficiente

Sistemas Operativos
34
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Domínio e Tipo de Sockets

• Domínio do socket - define a família de


protocolos associada a um socket:
– Internet: família de protocolos Internet
– Unix: comunicação entre processos da mesma máquina
– outros…
• Tipo do socket - define as características do canal
de comunicação:
– stream: canal com ligação, bidireccional, fiável, interface tipo
sequência de octetos
– datagram: canal sem ligação, bidireccional, não fiável,
interface tipo mensagem
– raw: permite o acesso directo aos níveis inferiores dos
protocolos (ex: IP na família Internet)

Sistemas Operativos
35
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 17
Domínio e Tipo de Sockets (II)

• Relação entre domínio, tipo de socket e protocolo:

tipo domínio AF_UNIX AF_INET AF_NS

SOCK_STREAM SIM TCP SPP

SOCK_DGRAM SIM UDP IDP

SOCK_RAW - IP SIM

SOCK_SEQPACKET - - SPP

Sistemas Operativos
36
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Sockets com e sem Ligação

• Sockets com ligação:


– Modelo de comunicação tipo diálogo
– Canal com ligação, bidireccional, fiável, interface tipo
sequência de octetos
• Sockets sem ligação:
– Modelo de comunicação tipo correio
– Canal sem ligação, bidireccional, não fiável, interface tipo
mensagem

Sistemas Operativos
37
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 18
Sockets sem Ligação

Servidor Cliente

socket socket

bind bind

sendto
recvfrom

sendto
recvfrom

Sistemas Operativos
38
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Sockets com Ligação

Servidor Cliente
socket

bind

listen socket

accept connect

read write

write read

Sistemas Operativos
39
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 19
Interface Sockets: definição dos
endereços
/* ficheiro <sys/socket.h> */ /* ficheiro <netinet/in.h> */
struct sockaddr { struct in_addr {
u_short family; /* definição do dominio u_long addr; /* Netid+Hostid */
(AF_XX)*/
char sa_data[14]; /* endereço específico
};
do dominio*/
}; struct sockaddr_in {

/* ficheiro <sys/un.h> */
u_short sin_family; /* AF_INET */
struct sockaddr_un { u_short sin_port; /* no. porto - 16 bits*/
u_short family; /* definição do struct in_addr sin_addr; /* IP addr */
domínio (AF_UNIX) */ char sin_zero[8]; /* não utilizado*/
char sun_path[108]; /* nome */ };
};
struct sockaddr struct sockaddr_un struct sockaddr_in
family family family
2-byte port
Endereço específico pathname 4-byte net ID, host ID
do domínio (up to 108 bytes) (unused)

Sistemas Operativos
40
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Interface Sockets: criação de um


socket e associação de um nome
• Criação de um socket:
#include <sys/types.h>
#include <sys/socket.h>
int socket (int dominio, int tipo, int protocolo);

– domínio: AF_UNIX, AF_INET


– tipo: SOCK_STREAM, SOCK_DGRAM
– protocolo: normalmente escolhido por omissão
– resultado: identificador do socket (sockfd)
• Um socket é criado sem nome
• A associação de um nome (endereço de comunicação) a um
socket já criado é feito com a chamada bind:

int bind(int sockfd, struct sockaddr *nome, int dim)

Sistemas Operativos
41
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 20
Sockets sem Ligação

sendto: Envia uma mensagem para o endereço especificado


int sendto(int sockfd, char *mens, int dmens,
int flag, struct sockaddr *dest, int *dim)
recvfrom: Recebe uma mensagem e devolve o endereço do
emissor
int recvfrom(int sockfd, char *mens, int dmens,
int flag, struct sockaddr *orig, int *dim)

Sistemas Operativos
42
Comunicação JAM, PJG, PF, CNR, JCCC, RR

unix.h e inet.h
inet.h
unix.h
#include <stdio.h>
#include <stdio.h> #include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#define UNIXSTR_PATH
"/tmp/s.unixstr"
#define UNIXDG_PATH #define SERV_UDP_PORT 6600
"/tmp/s.unixdgx" #define SERV_TCP_PORT 6601
#define UNIXDG_TMP #define SERV_HOST_ADDR "193.136.128.20 “
"/tmp/dgXXXXXXX" /* endereço do servidor */
#define SERV_HOSTNAME “mega"
/* nome do servidor */
Sistemas Operativos
43
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 21
Servidor DGRAM AF_UNIX

/* Servidor do tipo socket datagram. Recebe linhas do cliente e devolve-as para o cliente */
#include "unix.h"
main (void) {
int sockfd, servlen;
struct sockaddr_un serv_addr, cli_addr;
/* Cria socket datagram */
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
err_dump("server: can't open datagram socket");
unlink(UNIXDG_PATH);

bzero((char *) &serv_addr, sizeof(serv_addr));


serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXDG_PATH);
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
/* Associa o socket ao ficheiro */
if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
err_dump("server: can't bind local address");

/* Fica à espera de mensagens do cliente.


As mensagens recebidas são reenviadas para o cliente */
dg_echo(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr));
}
Sistemas Operativos
44
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Servidor DGRAM AF_UNIX (II)


#define MAXLINE 512
int n, clilen;
char mesg[MAXMESG];
/* Servidor do tipo socket datagram.
Manda linhas recebidas de volta
for (;;) {
para o cliente */
clilen = maxclilen;

#include <sys/types.h> /* Lê uma linha do socket */


#include <sys/socket.h> n = recvfrom(sockfd, mesg, MAXMESG,
#define MAXMESG 2048 0, pcli_addr, &clilen);
if (n < 0)
/* pcli_addr especifica o cliente */ err_dump("dg_echo:recvfrom error");

dg_echo(sockfd, pcli_addr, maxclilen) /*Manda linha de volta para o socket */


int sockfd; if (sendto(sockfd, mesg, n, 0,
pcli_addr, clilen) != n)
struct sockaddr *pcli_addr;
err_dump("dg_echo: sendto error");
int maxclilen;
}
{
}
Sistemas Operativos
45
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 22
Cliente DGRAM AF_UNIX
#include "unix.h"
main(void) {
int sockfd, clilen, servlen;
char *mktemp();
struct sockaddr_un cli_addr, serv_addr;

/* Cria socket datagram */


if(( sockfd = socket(AF_UNIX, SOCK_DGRAM, 0) ) < 0)
err_dump("client: can't open datagram socket");
/* Client will bind to an address so the server will get an address
in its recvfrom call and use it to send data back to the client. */
bzero((char *) &cli_addr, sizeof(cli_addr));
cli_addr.sun_family = AF_UNIX;
mktemp(cli_addr.sun_path);
clilen = sizeof(cli_addr.sun_family) + strlen(cli_addr.sun_path);

/* Associa o socket ao ficheiro temporário */


if (bind(sockfd, (struct sockaddr *) &cli_addr, clilen) < 0)
err_dump("client: can't bind local address");

Sistemas Operativos
46
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Cliente DGRAM AF_UNIX(II)


/* Primeiro uma limpeza preventiva */
bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXDG_PATH);
servlen=sizeof(serv_addr.sun_family) +
strlen(serv_addr.sun_path);

/* Lê linha do stdin e envia para o servidor. Recebe a linha do


servidor e envia-a para stdout */
dg_cli(stdin, sockfd, (struct sockaddr *) &serv_addr, servlen);

close(sockfd);
unlink(cli_addr.sun_path);
exit(0);
}

Sistemas Operativos
47
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 23
Cliente DGRAM AF_UNIX (III)
#include <stdio.h>
#define MAXLINE 512

/* Cliente do tipo socket datagram.


Lê string de fp e envia para sockfd.
Lê string de sockfd e envia para stdout */

#include <sys/types.h>
#include <sys/socket.h>

dg_cli(fp, sockfd, pserv_addr, servlen)


FILE *fp;
int sockfd;
struct sockaddr *pserv_addr;
int servlen;
{
int n;
static char sendline[MAXLINE], recvline[MAXLINE+1];
struct sockaddr x;
int xx = servlen;
Sistemas Operativos
48
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Cliente DGRAM AF_UNIX (IV)


while (fgets(sendline, MAXLINE, fp) != NULL) {
n = strlen(sendline);

/* Envia string para sockfd. Note-se que o \0 não é enviado */


if (sendto(sockfd, sendline, n, 0, pserv_addr, servlen) != n)
err_dump("dg_cli: sendto error on socket");

/* Tenta ler string de sockfd. Note-se que tem de


terminar a string com \0 */
n = recvfrom(sockfd, recvline, MAXLINE, 0,
(struct sockaddr *) 0, (int *) 0);
if (n < 0) err_dump("dg_cli: recvfrom error");
recvline[n] = 0;

/* Envia a string para stdout */


fputs(recvline, stdout);
}
if (ferror(fp)) err_dump("dg_cli: error reading file");
}
Sistemas Operativos
49
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 24
Sockets com Ligação

• listen - indica que se vão receber ligações neste socket:


int listen (int sockfd, int maxpendentes)
• accept - aceita uma ligação:
– espera pelo pedido de ligação
– cria um novo socket
– devolve:
» identificador do novo socket
» endereço do interlocutor
int accept(int sockfd, struct sockaddr *nome, int *dim)
• connect - estabelece uma ligação com o interlocutor cujo
endereço é nome:
int connect (int sockfd, struct sockaddr *nome, int dim)

Sistemas Operativos
50
Comunicação JAM, PJG, PF, CNR, JCCC, RR

unix.h e inet.h
inet.h
unix.h
#include <stdio.h>
#include <stdio.h> #include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#define UNIXSTR_PATH
"/tmp/s.unixstr"
#define UNIXDG_PATH #define SERV_UDP_PORT 6600
"/tmp/s.unixdgx" #define SERV_TCP_PORT 6601
#define UNIXDG_TMP #define SERV_HOST_ADDR "193.136.128.20 “
"/tmp/dgXXXXXXX" /* endereço do servidor */
#define SERV_HOSTNAME “mega"
/* nome do servidor */
Sistemas Operativos
51
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 25
Servidor STREAM AF_UNIX (main)
/* Recebe linhas do cliente e reenvia-as para o servlen = strlen(serv_addr.sun_path) +
cliente */ sizeof(serv_addr.sun_family);
#include "unix.h" if (bind(sockfd, (struct sockaddr *)
&serv_addr, servlen) < 0)
main(void) { err_dump("server, can't bind local address");
int sockfd, newsockfd, clilen, childpid, servlen; listen(sockfd, 5);
struct sockaddr_un cli_addr, serv_addr; for (;;) {
clilen = sizeof(cli_addr);
/* Cria socket stream */ newsockfd = accept(sockfd,(struct sockaddr *)
if((sockfd = socket(AF_UNIX,SOCK_STREAM,0) ) < 0) &cli_addr, &clilen);
err_dump("server: can't open stream socket"); if(newsockfd<0)
err_dump("server: accept error");
/* O nome serve para que os clientes possam /*Lança processo filho para tratar com o cliente*/
identificar o servidor */ if ((childpid = fork()) < 0)
bzero((char *)&serv_addr, sizeof(serv_addr)); err_dump("server: fork error");
serv_addr.sun_family = AF_UNIX; else if (childpid == 0) {
strcpy(serv_addr.sun_path, UNIXSTR_PATH); /* Código do filho */
close(sockfd); // Não é utilizado pelo filho
/* Elimina o ficheiro, para o caso de algo ter str_echo(newsockfd);
ficado pendurado. exit(0);
unlink(UNIXSTR_PATH); }
/* Código do pai */
close(newsockfd); // Não é utilizado pelo pai
} // for } // main
Sistemas Operativos
52
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Servidor STREAM AF_UNIX


(str_echo)
#define MAXLINE 512
/* Reenvia a linha para o socket. n
/* Servidor do tipo socket stream. conta com o \0 da string, caso
Reenvia as linhas recebidas para o contrário perdia-se sempre um
cliente */
caracter! */
str_echo(int sockfd) if (writen(sockfd, line, n) != n)
{ err_dump("str_echo: writen error");
int n; }
char line[MAXLINE]; }

for (;;) {
/* Lê uma linha do socket */
n = readline(sockfd, line, MAXLINE);
if (n == 0) return;
else if (n < 0)
err_dump("str_echo: readln err");

Sistemas Operativos
53
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 26
Cliente STREAM AF_UNIX (main)
/* Cliente do tipo socket stream.
#include "unix.h" /*Estabelece uma ligação. Só funciona se o
main(void) { sockt tiver sido criado e o nome associado*/
int sockfd, servlen; if(connect(sockfd, (struct sockaddr *)
struct sockaddr_un serv_addr;
&serv_addr, servlen) < 0)
/* Cria socket stream */
err_dump("clnt:can't connect to serv");

if ((sockfd= socket(AF_UNIX,SOCK_STREAM,0))< 0) /*Envia as linhas lidas do teclado */


err_dump("client: can't open stream socket"); str_cli(stdin, sockfd);

/* Primeiro uma limpeza preventiva */


/* Fecha o socket e termina */
bzero((char *) &serv_addr, sizeof(serv_addr));
close(sockfd);
exit(0);
/* Dados para o socket stream: tipo + nome do }
ficheiro.O nome identifica o servidor */

serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXSTR_PATH);
servlen = strlen(serv_addr.sun_path) +
sizeof(serv_addr.sun_family);

Sistemas Operativos
54
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Cliente STREAM AF_UNIX (str_cli)


#include <stdio.h>
#define MAXLINE 512 /* Envia string para sockfd. Note-se que o
\0 não é enviado */
/* Lê string de fp e envia para sockfd.
Lê string de sockfd e envia para stdout */ n = strlen(sendline);
str_cli(fp, sockfd) if (writen(sockfd, sendline, n) != n)
FILE *fp; err_dump("str_cli: write err");
int sockfd; /* Tenta ler string de sockfd. Note-se
{ que tem de terminar a string com \0 */
int n; n = readline(sockfd, recvline,
char sendline[MAXLINE], MAXLINE);
recvline[MAXLINE+1]; if (n<0) err_dump("str_cli:read err");
recvline[n] = 0;
while (fgets(sendline, MAXLINE, fp) /* Envia a string para stdout */
!= NULL) { fputs(recvline, stdout);

} /* while */
if (ferror(fp))
err_dump("str_cli: err read file");
}
Sistemas Operativos
55
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 27
Utilitários
/* Escreve nbytes num ficheiro/socket. /* Lê uma linha de até \n, maxlen ou \0.
Bloqueia até conseguir escrever os Bloqueia até ler a linha ou dar erro.
nbytes ou dar erro */
int writen(int fd, char* ptr, int nbytes){ Retorna quantos caracteres conseguiu ler */
int nleft, nwritten; int readline(int fd, char* ptr, int maxlen) {
nleft = nbytes; int n, rc; char c;
while (nleft > 0) { for (n=1; n < maxlen; n++) {
nwritten = write(fd, ptr, nleft); if ((rc = read(fd, &c, 1)) == 1) {
if (nwritten <= 0) return(nwritten); *ptr++ = c;
nleft -= nwritten; if (c == '\n') break;
ptr += nwritten;
} else if (rc == 0) {
}
return(nbytes - nleft); if (n == 1) return(0);
} else break;
} else return (-1);
}
#include <stdio.h> /* Não esquecer de terminar a string */
#include <errno.h> *ptr = 0;
/* Mensagem de erro */ /* Note-se que n foi incrementado de modo a contar
err_dump(char* msg) { com o \n ou \0 */
perror(msg); return (n);
exit(1); }
}

Sistemas Operativos
56
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Espera Múltipla com Select


• select:
#include <sys/select.h>
#include <sys/time.h>
int select (int maxfd, fd_set* leitura, fd_set* escrita, fd_set* excepcao, struct timeval* alarme)
– espera por um evento
– bloqueia o processo até que um descritor tenha dados disponíveis ou até
expirar o alarme
– especifica um conjunto de descritores onde espera:
» receber mensagens
» receber notificações de mensagens enviadas (envios assíncronos)
» receber notiticações de acontecimentos excepcionais
• exemplos de quando o select retorna quando:
– qualquer dos descritores (1,4,5) está pronto para leitura
– qualquer dos descritores (2,7) está pronto para escrita
– qualquer dos descritores (1,4) tem uma condição excepcional pendente
– já passaram 10 segundos

Sistemas Operativos
57
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 28
Espera Múltipla com Select (cont.)

struct timeval {
long tv_sec; /* seconds /*
tv_usec; /* microseconds /*
}
• esperar para sempre (alarme é null pointer)
• esperar um intervalo de tempo fixo (alarme com o tempo
respectivo)
• não esperar (alarme com valor zero nos segundos e
microsegundos)

• as condições de excepção actualmente suportadas são:


– chegada de dados out-of-band
– informação de controlo associada a pseudo-terminais

Sistemas Operativos
58
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Manipulação do fd_set

• como indicar no select quais os descritores que se


pretende “monitorar”?
– void FD_ZERO (fd_set* fdset) - clear all bits in fdset
– void FD_SET (int fd, fd_set* fd_set) - turn on the bit for fd in fdset
– void FD_CLR (int fd, fd_set* fd_set) - turn off the bit for fd in fdset
– int FD_ISSET (int fd, fd_set* fd_set) - is the bit for fd on in fdset?

• de modo a indicar quais os decritores que estão prontos, a


função select modifica:
– fd_set* leitura
– fd_set* escrita
– fd_set* excepcao

Sistemas Operativos
59
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 29
Servidor com Select
/* Servidor que utiliza sockets stream e
datagram em simultâneo. int main(void) {
O servidor recebe caracteres e envia-os int strmfd,dgrmfd,newfd;
para stdout */ struct sockaddr_un servstrmaddr,servdgrmaddr,clientaddr;
int len,clientlen;
#include <stdio.h> fd_set testmask,mask;
#include <sys/types.h>
#include <sys/time.h> /* Cria socket stream */
#include <sys/socket.h> if((strmfd=socket(AF_UNIX,SOCK_STREAM,0))<0){
#include <sys/un.h> perror(ERRORMSG1);
#include <errno.h> exit(1);
}
bzero((char*)&servstrmaddr,
#define MAXLINE 80
sizeof(servstrmaddr));
#define MAXSOCKS 32
servstrmaddr.sun_family = AF_UNIX;
strcpy(servstrmaddr.sun_path,UNIXSTR_PATH);
#define ERRORMSG1 "server: cannot open stream len = sizeof(servstrmaddr.sun_family)
socket" +strlen(servstrmaddr.sun_path);
#define ERRORMSG2 "server: cannot bind stream unlink(UNIXSTR_PATH);
socket" if(bind(strmfd,(struct sockaddr *)&servstrmaddr, len)<0)
#define ERRORMSG3 "server: cannot open {
datagram socket" perror(ERRORMSG2);
#define ERRORMSG4 "server: cannot bind exit(1);
datagram socket"
Sistemas Operativos }
#include "names.h" 60
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Servidor com Select (II)


/*Servidor suporta 5 clientes pendentes
no socket stream*/
/*
listen(strmfd,5);
- Primeiro limpa-se tudo.
/* Cria socket datagram */
- Em seguida, mascaram-se os 2 sockets stream
if((dgrmfd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0) {
e datagram.
perror(ERRORMSG3);
- A mascara é limpa pelo sistema de cada vez
exit(1); que algo é recebido no socket. Por isso se
} utiliza uma mascara auxiliar
/*Inicializa socket datagram: tipo + */
nome do ficheiro*/ FD_ZERO(&testmask);
bzero((char *)&servdgrmaddr,sizeof(servdgrmaddr));
servdgrmaddr.sun_family = AF_UNIX;
FD_SET(strmfd,&testmask);
strcpy(servdgrmaddr.sun_path,UNIXDG_PATH); FD_SET(dgrmfd,&testmask);
/* O servidor é quem cria o ficheiro que identifica o
socket. Em seguida associa o socket ao ficheiro. A
dimensão a indicar ao bind não é a da estrutura, pois
depende do nome do ficheiro */
len=sizeof(servdgrmaddr.sun_family)+
strlen(servdgrmaddr.sun_path);
unlink(UNIXDG_PATH);
if(bind(dgrmfd,(struct sockaddr *)&servdgrmaddr,len)<0)
{
perror(ERRORMSG4);
exit(1);
} Sistemas Operativos
61
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 30
Servidor com Select (III)
for(;;) {
mask = testmask;

/* Bloqueia servidor até que aconteça algo. */


select(MAXSOCKS,&mask,0,0,0);
/* Verificar se chegaram clientes para osocket stream */
if(FD_ISSET(strmfd,&mask)) {
/* Aceitar o cliente e associa-lo a newfd. */
clientlen = sizeof (clientaddr);
newfd = accept(strmfd,(struct sockaddr*)&clientaddr, &clientlen);
echo(newfd);
close(newfd);
}
/* Verificar se chegaram dados ao socket datagram. Ler dados */
if(FD_ISSET(dgrmfd,&mask))
echo(dgrmfd);
/*Voltar ao ciclo mas não esquecer da mascara! */
}
}

Sistemas Operativos
62
Comunicação JAM, PJG, PF, CNR, JCCC, RR

unix.h e inet.h
inet.h
unix.h
#include <stdio.h>
#include <stdio.h> #include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#define UNIXSTR_PATH
"/tmp/s.unixstr"
#define UNIXDG_PATH #define SERV_UDP_PORT 6600
"/tmp/s.unixdgx" #define SERV_TCP_PORT 6601
#define UNIXDG_TMP #define SERV_HOST_ADDR "193.136.128.20 “
"/tmp/dgXXXXXXX" /* endereço do servidor */
#define SERV_HOSTNAME “mega"
/* nome do servidor */
Sistemas Operativos
63
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 31
Servidor UDP AF_INET
/* Servidor do tipo socket udp (datagram). /* Associa o socket a qualquer clnt */
Recebe linhas do clnt e devolve-as para o clnt */ if (bind(sockfd,
(struct sockaddr *)&serv_addr,
#include "inet.h"
sizeof(serv_addr)) < 0)
err_dump("server: bind");
main(void) {
int sockfd;
/* Fica à espera de msgs do cliente.
struct sockaddr_in serv_addr, cli_addr;
As msgs recebidas são reenviadas */
/* Cria socket udp (datagram) */ dg_echo(sockfd,
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) (struct sockaddr *)&cli_addr,
err_dump("server: can't open datagram sizeof(cli_addr));
socket"); }

/* Primeiro uma limpeza preventiva!


Dados para o socket udp (datagram): tipo +
qualquer cliente */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_UDP_PORT);
Sistemas Operativos
64
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Servidor UDP AF_INET (cont.)


#define MAXLINE 512
for (;;) {
/* Servidor do tipo socket datagram.
Manda linhas recebidas de volta clilen = maxclilen;
para o cliente */

#include <sys/types.h>
/* Lê uma linha do socket */
#include <sys/socket.h> n = recvfrom(sockfd, mesg, MAXMESG, 0,
pcli_addr, &clilen);
#define MAXMESG 2048
if (n < 0) err_dump("dg_echo: recvfrom err");
/* pcli_addr especifica o cliente */
/* Manda linha de volta para o socket */
dg_echo(sockfd, pcli_addr, maxclilen)
if ( sendto(sockfd, mesg, n, 0,
int sockfd;
struct sockaddr *pcli_addr; pcli_addr, clilen) != n)
int maxclilen; err_dump("dg_echo: sendto err");
{
}
int n, clilen;
char mesg[MAXMESG]; }

Sistemas Operativos
65
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 32
Cliente UDP AF_INET
/* Cria socket udp (datagram) */
/* Cliente do tipo socket udp (datagram). if ((sockfd = socket(AF_INET, SOCK_DGRAM,
Lê linhas de stdin, envia para o servidor,
recebe-as 0)) < 0)
de novodo servidor e envia-as para stdout */ err_dump("clnt: datagram socket");
#include "inet.h" /* Associa o socket a qualquer endereço. Esta
associação serve para ter um socket funcional mas
main(void) { não ligado a um servidor */
int sockfd; bzero((char*)&cli_addr, sizeof(cli_addr));
struct sockaddr_in cli_addr, serv_addr; cli_addr.sin_family = AF_INET;
struct hostent *hp;
cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/* Primeiro uma limpeza preventiva! cli_addr.sin_port = htons(0);
Dados para o socket udp (datagram): tipo */ if (bind(sockfd, (struct sockaddr *)&cli_addr,
bzero((char*)&serv_addr, sizeof(serv_addr)); sizeof(cli_addr)) < 0)
serv_addr.sin_family = AF_INET; err_dump(“clnt: bind");
/* Lê linha do stdin e envia para o server. Recebe
/* Obter endereço do servidor a partir do nome a linha do serv e envia-a para stdout */
*/
dg_cli(stdin,sockfd,(struct sockaddr*)&serv_addr,
hp = gethostbyname(SERV_HOSTNAME); sizeof(serv_addr));

/* Dados para o socket udp (datagram)*/ /* Fecha o socket */


bcopy (hp->h_addr_list[0],
close(sockfd);
(char*)&serv_addr.sin_addr.s_addr,
hp->h_length); exit(0);
serv_addr.sin_port = htons(SERV_UDP_PORT); }

Sistemas Operativos
66
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Cliente UDP AF_INET (cont.)


/* Envia string para sockfd. Note-se que o \0 não é
#include <stdio.h> enviado */
#define MAXLINE 512
if (sendto(sockfd, sendline, n, 0,
pserv_addr, servlen) != n)
/* Cliente do tipo socket datagram.
err_dump("dg_cli: sendto error on
Lê string de fp e envia para sockfd. socket");
Lê string de sockfd e envia p/ stdout
*/ /* Tenta ler string de sockfd. Note-se que tem de
#include <sys/types.h> terminar a string com \0 */
#include <sys/socket.h>
n = recvfrom(sockfd, recvline, MAXLINE,
dg_cli(FILE* fp, int sockfd, 0, (struct sockaddr *)&x, &xx);
struct sockaddr * pserv_addr, if (n < 0) err_dump("dg_cli: recvfrom error");
int servlen) { recvline[n] = 0;
int n;
char sendline[MAXLINE], /* Envia a string para stdout */
recvline[MAXLINE+1];
fputs(recvline, stdout);
struct sockaddr x;
}
int xx = servlen;
if (ferror(fp)) err_dump("dg_cli: error reading
while (fgets(sendline, MAXLINE, fp) != file");
NULL) {
}
n = strlen(sendline);
Sistemas Operativos
67
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 33
Servidor TCP AF_INET
/* Servidor do tipo socket tcp (stream).
Recebe linhas do cliente e reenvia-as para o cliente */ /* Servidor pronto a aceitar 5 clientes para o socket tcp (stream) */
#include "inet.h" listen(sockfd, 5);
main(void) { for ( ; ; ) {
int sockfd, newsockfd, clilen, childpid; /* Não esquecer que quando o servidor aceita um cliente
struct sockaddr_in cli_addr, serv_addr; cria um socket para comunicar com ele; o primeiro
socket (sockfd) fica à espera de mais clientes */
/* Cria socket stream */ clilen = sizeof(cli_addr);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr,
err_dump("server: can't open socket"); &clilen);
if (newsockfd < 0) err_dump("server: accept error");
/* Primeiro uma limpeza preventiva; dados para o
/* Lança processo filho para lidar com o cliente */
socket stream: tipo + qualquer endereço; note-se
que o servidor aceita qualquer endereço de cliente */ else if ((childpid = fork()) < 0) err_dump("server: fork error");
else if (childpid == 0) {
bzero((char*)&serv_addr, sizeof(serv_addr)); /* Processo filho que vai atender o cliente; fechar
serv_addr.sin_family = AF_INET; sockfd é indicado, já que não é utilizado pelo
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); processo filho; os dados recebidos do cliente
são reenviados para o cliente */
serv_addr.sin_port = htons(SERV_TCP_PORT);
close (sockfd);
str_echo(newsockfd);
/* Associa o socket (a qualquer endereço de cliente) */
exit(0);
if (bind(sockfd, (struct sockaddr *)&serv_addr, }
sizeof(serv_addr)) < 0)
err_dump("server: can't bind local address"); /* Processo pai; fechar newsockfd é indicado, já que não é
Sistemas Operativos utilizado pelo processo pai */
close (newsockfd); 68
Comunicação JAM, PJG, PF, CNR, JCCC, RR
}
}

Servidor TCP AF_INET (cont.)


#define MAXLINE 512

/* Servidor do tipo socket stream.


Manda linhas recebidas de volta para o cliente */

str_echo(int sockfd) {
int n;
char line[MAXLINE];

for (;;) {
/* Lê uma linha do socket */
n = readline(sockfd, line, MAXLINE);
if (n == 0) return;
else if (n < 0) err_dump("str_echo: readline error");

/* Manda linha de volta para o socket. n conta com


o \0 da string, caso contrário perdia-se sempre
um caracter! */
if (writen(sockfd, line, n) != n) err_dump("str_echo: writen error");
}
}
Sistemas Operativos
69
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 34
Cliente TCP AF_INET
/* Cliente do tipo socket tcp (stream). /* Dados para o socket stream: informação sobre o servidor */
Lê linhas do teclado e envia-as para o servidor */ bcopy (hp->h_addr_list[0], (char*)&serv_addr.sin_addr.s_addr,
hp->h_length);
#include "inet.h" serv_addr.sin_port = htons(SERV_TCP_PORT);

main(void) { /* Cria socket tcp (stream) */


int sockfd; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
struct sockaddr_in serv_addr; err_dump("client: can't open datagram socket");
struct hostent *hp;
/* Estabelece ligação com o servidor */
/* Primeiro uma limpeza preventiva! if (connect(sockfd, (struct sockaddr*) &serv_addr,
Dados para o socket stream: tipo */ sizeof(serv_addr)) < 0)
err_dump("client:can't connect to server");
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; /* Envia as linhas lidas do teclado para o socket */
str_cli(stdin, sockfd);
/* Obter endereço do servidor a partir do seu nome */
hp = gethostbyname(SERV_HOSTNAME); /* Fecha o socket e termina */
close (sockfd);
exit(0);
}
Sistemas Operativos
70
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Cliente TCP AF_INET (cont.)


#include <stdio.h>
#define MAXLINE 512
/* Tenta ler string de sockfd. Note-se que tem de
/* Cliente do tipo socket stream. terminar a string com \0 */
Lê string de fp e envia para sockfd. n = readline(sockfd, recvline, MAXLINE);
Lê string de sockfd e envia para stdout */ if (n<0) err_dump("str_cli:readline error");
recvline[n] = 0;
str_cli(FILE* fp, int sockfd) {
int n; /* Envia a string para stdout */
char sendline[MAXLINE], recvline[MAXLINE+1]; fputs(recvline, stdout);
}
if (ferror(fp)) err_dump("str_cli: error reading file");
while (fgets(sendline, MAXLINE, fp) != NULL) {
}
/* Envia string para sockfd;
note-se que o \0 não é enviado */
n = strlen(sendline);
if (writen(sockfd, sendline, n) != n)
err_dump("str_cli: writen error on socket");

Sistemas Operativos
71
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 35
Ordenação de Bytes

• htonl:
– convert host-to-network, long integer
• htons:
– convert host-to-network, short integer
• ntohl:
– convert network-to-host, long integer
• ntohs:
– convert network-to-host, short integer

Sistemas Operativos
72
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Memória Partilhada (Unix)

Sistemas Operativos
73
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 36
Memória Partilhada

• permite o acesso de vários processos • associação a uma região:


a uma zona de memória comum
char* shmat (int shmid,
• a dimensão do segmento não pode
ser alterada depois da criação char *shmaddr,
• cada processo pode “ver” o segmento int shmflg)
em endereços distintos do seu espaço
de endereçamento • devolve o endereço base da região
• criação de uma região: • o endereço é especificado por shmaddr
#include <sys/types.h> • o endereço é calculado pelo sistema se
#include <sys/ipc.h> shmaddr for zero
#include <sys/shm.h> • se shmflg = SHM_RDONLY o acesso fica
int shmget (key_t key, int sz, restrito a leitura
int shmflg) • eliminação da associação:
• sz especifica a dimensão da região int shmdt (char *shmaddr);
em bytes
Sistemas Operativos
74
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Memória Partilhada - Controlo


Ö comandos possíveis:
• sintaxe: Š IPC_STAT preenche buf com estado actual
int shmctl (shmid, cmd, buf)
Š IPC_SET inicializa parametros a partir de buf
int shmid, cmd;
struct shmid_ds *buf; Š IPC_RMID elimina a memória partilhada

• a estrutura shmid_ds (mantida no núcleo para cada região


de memória partilhada) contém:
ipc_perm shm_perm; /*permissões*/
int shm_segsz; /*dimensão em bytes*/
ushort shm_cpid; /*pid do criador*/
ushort shm_lpid; /*pid do último shmop*/
ushort shm_nattch; /*#actual de ligações*/
time_t shm_atime; /*data último shmat*/
time_t shm_dtime; /*data último shmdt*/
time_t shm_ctime; /*data última modif.*/
Sistemas Operativos
75
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 37
Exemplo: Memória Partilhada
/* consumidor*/ main() {
IdRegPart = shmget (CHAVEMEM, 1024, 0777);
if (IdRegPart <0)
#include <stdio.h>
perror("shmget:");
#include <sys/types.h>
#include <sys/ipc.h> Apint=(int*)shmat(IdRegPart, (char *)0, 0);
#include <sys/shm.h> if(Apint == (int *) -1)
perror("shmat:");
#define CHAVEMEM 10
printf(" mensagem na regiao de memoria partilhada \n");
int IdRegPart; for (i = 0; i<256; i++)
int *Apint; printf ("%d ", *Apint++);
int i;
printf (" \n liberta a regiao partilhada \n");
shmctl (IdRegPart, 0, IPC_RMID,0);
}

Sistemas Operativos
76
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Exemplo: Memória Partilhada


(cont.)

main () {
/* produtor */
IdRegPart = shmget (CHAVEMEM, 1024, 0777| IPC_CREAT);
if (IdRegPart<0) perror(" shmget:");
#include <stdio.h>
#include <sys/types.h>
printf (" criou uma regiao de identificador %d \n",
#include <sys/ipc.h>
IdRegPart);
#include <sys/shm.h>

Apint = (int *)shmat (IdRegPart, (char *) 0, 0);


#define CHAVEMEM 10
if (Apint == (int *) -1) perror("shmat:");
int IdRegPart;
int *Apint;
for (i = 0; i<256; i++) *Apint++ = i;
int i;
}

Sistemas Operativos
77
Comunicação JAM, PJG, PF, CNR, JCCC, RR

Page 38

Você também pode gostar