Pipe ile Client-Server Uygulamalar
Client-server program mimarisinde gerçek işlemleri yapan programa server denir. Server
programı genellikle bir tanedir. Client programlar process’ler arası haberleşme
yöntemlerinden birisiyle server programa bilgi göndererek server’ın kendileri için bir şeyler
yapmasını isterler. Server program client programdan gelen işlem isteklerini yerine getirir ve
sonucu yine process’ler arası haberleşme yöntemiyle client programa iletir. Genellikle bir
server programa birden fazla client program bağlanabilir. Client programların birbirleriyle
genellikle bir ilişkisi olmaz. Bunlar server program yoluyla birbirleriyle ilişki kurarlar. Basit
bir chat programında tipik olarak client sisteme girdiği zaman server’a mesaj göndererek
sisteme girdiğini belirtir. Herhangi bir client mesaj yazdığında bu mesaj server’a iletilir.
Server da bu mesajı tüm client’lara dağıtır. ICQ gibi çok fazla kişi tarafından kullanılan
mesajlaşma programlarında client’lar birbirleri arasında yine client-server olarak
haberleşmektedir. Client ve server arasındaki haberleşmelerde genellikle bir yapı kullanılır.
Kullanılan yapının değişken uzunlukta olması daha etkin bir kullanımdır. Haberleşme için
kullanılan tipik bir yapı şöyle olabilir.
typedef struct _MSG {
WORD wType;
WORD wSize;
char buf[1]; // C++’ta char buf[] şeklinde olabilir.
// Bu durumda yapının uzunluğuna
// etki etmez.
} MSG;
Burada wType elemanı yapılacak işlemin türünü belirtir. Her mesajın ne amaçlı olarak
gönderildiğini belirten bir tür bilgisi ve bir data bilgisi vardır. wSize data bilgisinin
uzunluğunu tutar. Mesajı okuyan taraf önce
2 * sizeof(WORD)
kadar bilgiyi okuduktan sonra size kısmının uzunluğuna göre mesajın datalarını okur.
İsimli pipe’larla client-server uygulamalarda, client’lar server’a tek bir pipe üzerinden
mesajlarını gönderebilirler. (Tabi gönderilecek mesajın uzunluğunun PIPE_BUF değerini
aşmaması gerekir). Ancak server client’larla tek bir pipe üzerinden haberleşemez. Çünkü bir
client’ın yalnızca kendisine gönderilen bilgiyi alması gerekir. Bu durumda bir client server’a
bağlandığında server’ın o client için yeni bir pipe yaratması gerekir. Mesaj kuyruğu (Message
Queue) denilen process’ler arası haberleşme yönteminin bloke mekanizması tamamen pipe’a
benzemektedir. Ancak bu sistemde her mesajın bir ID değeri vardır ve process yalnızca belli
bir ID’ye sahip mesajları alabilir.
Sınıf çalışması: Aşağıda belirtilen basit client server uygulamayı isimli pipe kullanarak
yazınız.
Açıklamalar:
1) Mesajın genel formatı şöyledir:
typedef struct _MSG {
int type;
int length;
char buf[1];
}MSG;
type değişkeni enum { MSG1, MSG2, MSG3, MSG4, MSG5 }; sabitlerinden biri
olabilir.
2) Server önce mesajın türü ve uzunluğunu okur. Uzunluk buf kısmının uzunluğudur. Server
mesajı pipe’dan alarak aşağıdaki biçimde display eder:
Message No N Received: "buf içerisindeki yazı"
3) Client program bir döngü içerisinde programcıdan bir yazı ve mesaj numarası isteyecek.
Yazıyı buf kısmına yerleştirecek ve server’a pipe aracılığıyla bu yazıyı gönderecektir.
4) Sınıf çalışması kolay yapılsın diye server client’a mesaj göndermeyecektir. Client
klavyeden özel bir yazı girildiğinde sonlandırılacaktır.
5) Uygulamada pipe manuel açılıp manuel silinebilir. pipe ismi client ve server programları
tarafından ortak bir biçimde belirlenmiş olmalıdır.
/* pipeserver.c – server */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
C ve Sistem Programcıları Derneği 110
#include <fcntl.h>
typedef struct _MSG {
int type;
int length;
char buf[1];
} MSG;
int main(void)
{
char temp[1024];
int cs, n;
int length;
char *pMSG;
while (1) {
cs = open("cs.pip", O_RDONLY);
if (read(cs, temp, sizeof(int) * 2) == 0)
exit(1);
n = *((int *) temp);
length = *(((int *) temp) + 1);
read(cs, temp + sizeof(int) * 2, length);
temp[sizeof(int) * 2 + length] = '\0';
printf("MSG no: %d\n", n);
printf("MSG: %s\n", temp + sizeof(int) * 2);
}
return 0;
}
/* pipeclient.c – client */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct _MSG {
int type;
int length;
char buf[1];
} MSG;
int main(int argc, char *argv[])
{
char temp[1024];
int cs, n;
char *pMSG;
while (1) {
printf("MSG no:");
scanf("%d", &n);
getchar();
if (n == -1)
exit(1);
printf("MSG: ");
gets(temp);
pMSG = (char *) malloc(sizeof(MSG) + strlen(temp) + 1);
*((int *) pMSG) = n;
*(((int *) pMSG) + 1) = sizeof(temp);
strcpy(pMSG + sizeof(int) * 2, temp);
cs = open("cs.pip", O_WRONLY);
C ve Sistem Programcıları Derneği 111
if (cs < 0) {
fprintf(stderr, "cannot open pipe...\n");
exit(1);
}
write(cs, pMSG, sizeof(MSG) + strlen(temp));
}
return 0;
}