UNIX Soketleri
UNIX alan soketleri (UNIX domain socket), Internet soketlerinin aksine, yalnız aynı makina üzerindeki proseslerin haberleşmesine imkan tanımaktadır. Internet soketlerinde olduğu gibi TCP ve UDP üzerinden haberleşme sağlanabilir.
UNIX alan soketi oluşturmak için socket fonksiyonuna ilk argüman olarak AF_UNIX sembolik sabitini geçirmeliyiz. Alan soketleri dosya sisteminde bir giriş oluşturmakta ve buna ilişkin bir yol ifadesi (pathname) almaktadır. Alan soketlerinin adresleri sockaddr_un yapı türünde saklanmaktadır.
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[108]; // Null karakter ile sonlandırılmış soket yol ismi
};
Soket bind edildiğinde dosya sisteminde sokete ilişkin bir giriş oluşturulacaktır. Aşağıdaki örneği çalıştırıp bu durumu gözleyebiliriz.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define UNIXSOCKNAME "/tmp/unixsock"
int main() {
int sfd;
struct sockaddr_un addr;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
return 1;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, UNIXSOCKNAME, sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
return 1;
return 0;
}
$ gcc -oserver server.c
$ ./server
$ ls -l /tmp/unixsock
srwxrwxr-x 1 serkan serkan 0 Mar 25 17:24 /tmp/unixsock
ls çıktısının başındaki s karakteri dosyanın bir sokete ilişkin olduğunu göstermektedir.
Basit bir örnek üzerinden, stream soketlerini kullanarak, sunucu ve istemci haberleşmesine bakalım. İstemci klavyeden girilen yazıyı sunucuya göndermektedir.
server.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define UNIXSOCKNAME "/tmp/unixsock"
#define BUF_SIZE 100
#define BACKLOG 5
int main() {
struct sockaddr_un addr;
int sfd, cfd;
ssize_t numRead;
char buf[BUF_SIZE];
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
return 1;
unlink(UNIXSOCKNAME);
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, UNIXSOCKNAME, sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
return 1;
if (listen(sfd, BACKLOG) == -1)
return 1;
for (;;) {
cfd = accept(sfd, NULL, NULL);
if (cfd == -1)
return 1;
while ((numRead = read(cfd, buf, BUF_SIZE)) > 0) {
if (write(1, buf, numRead) != numRead)
return 1;
}
close(cfd);
}
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define UNIXSOCKNAME "/tmp/unixsock"
#define BUF_SIZE 100
int main()
{
struct sockaddr_un addr;
int sfd;
ssize_t numRead;
char buf[BUF_SIZE];
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
return 1;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, UNIXSOCKNAME, sizeof(addr.sun_path) - 1);
if (connect(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
return 1;
while ((numRead = read(0, buf, BUF_SIZE)) > 0) {
if (write(sfd, buf, numRead) != numRead)
return 1;
}
}
$ gcc -oserver server.c
$ gcc -oclient client.c