Pemrograman socket menggunakan sistem client-server, dimana proses client berbicara dengan proses server dan sebaliknya. Contoh, client dengan aplikasi telnet akan menghubungi server yang menjalankan aplikasi telnetd.

Gambar 8.1 Client-Server
Diagram alir yang digunakan tampak pada;

Gambar 8.2 Diagram Alir Program Berbasis Connection-oriented

Gambar 8.3 Diagram Alir Program Berbasis Connectionless-oriented
1. Contoh Server Berbasis STREAM
/*
** server.c - a stream socket server demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define MYPORT 3490 // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
void sigchld_handler(int s)
{ while(wait(NULL) > 0);
}
int main(void)
{ int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector's address information int sin_size; struct sigaction sa; int yes=1;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1);
}
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1);
}
my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
{ perror("bind"); exit(1);
}
if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1);
} while(1) { // main accept() loop sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
&sin_size)) == -1) { perror("accept"); continue;
}
printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr)); if (!fork()) { // this is the child process close(sockfd); // child doesn't need the listener if (send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send");
close(new_fd); exit(0);
}
close(new_fd); // parent doesn't need this
} return 0;
}
Untuk mencoba program server tersebut jalankan:
# telnet server 3490
2. Contoh Client Berbasis STREAM
/*
** client.c - a stream socket client demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3490 // the port client will be connecting to
#define MAXDATASIZE 100 // max number of bytes we can get at once
int main(int argc, char *argv[])
{ int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he;
struct sockaddr_in their_addr; // connector's address information
if (argc != 2) { fprintf(stderr,"usage: client hostname\n"); exit(1);
}
if ((he=gethostbyname(argv[1])) == NULL) { // get the host info perror("gethostbyname"); exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1);
}
their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(PORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr))
== -1) { perror("connect"); exit(1);
}
if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); exit(1);
}
buf[numbytes] = '\0'; printf("Received: %s",buf);
close(sockfd); return 0;
}
Program ini mencari server dengan port 3490 dan menerima string dari server dan menampilkan ke layar.
3. Socket dengan DATAGRAM
Program listener akan bersiap pada sebuah mesin dan akan menunggu paket yang menuju ke port 4950. Program talker akan mengirim paket menuju ke port tersebut.
Listing program listernet:
~/*
** listener.c - a datagram sockets "server" demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 4950 // the port users will be connecting to
#define MAXBUFLEN 100
int main(void)
{ int sockfd;
struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector's address information int addr_len, numbytes; char buf[MAXBUFLEN];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1);
}
my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1) {
perror("bind"); exit(1);
}
addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd,buf, MAXBUFLEN-1, 0,(struct sockaddr
*)&their_addr, &addr_len)) == -1) { perror("recvfrom"); exit(1);
}
printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr)); printf("packet is %d bytes long\n",numbytes);
buf[numbytes] = '\0';
printf("packet contains \"%s\"\n",buf); close(sockfd);
return 0;
}
Listing program talker:
/*
** talker.c - a datagram "client" demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT 4950 // the port users will be connecting to
int main(int argc, char *argv[])
{ int sockfd;
struct sockaddr_in their_addr; // connector's address information struct hostent *he;
int numbytes;
if (argc != 3) { fprintf(stderr,"usage: talker hostname message\n"); exit(1);
}
if ((he=gethostbyname(argv[1])) == NULL) { // get the host info perror("gethostbyname"); exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1);
}
their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(MYPORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct
if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0,(struct sockaddr
*)&their_addr, sizeof(struct sockaddr))) == -1) { perror("sendto"); exit(1);
}
printf("sent %d bytes to %s\n", numbytes, inet_ntoa(their_addr.sin_addr));
close(sockfd); return 0;
}
4. Socket lanjutan
Pada bagian ini dijelaskan tentang penggunaan beberapa fungsi yang dapat mendukung kerja dari program jaringan menggunakan pemrograman socket.
4.1 Blocking
Suatu aplikasi server dapat menerima paket data secara bersamaan, untuk itu perlu dilakukan pelepasan suatu pembatas atau yang disebut non-blocking. Sehingga server bisa menerima data secara bersamaan.
Pada initialisasi socket(), socket secara awal memiliki nilai awal blocking. Untuk membuat mejadi bersifat non-blocking dilakukan dengan cara memanggil fungsi fcntl(). Hal ini dapat dilihat pada contoh berikut :
#include <unistd.h>
#include <fcntl.h>
.
.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
.
.
4.2. select() -- Synchronous I/O Multiplexing
Dengan fungsi select, aplikasi akan dapat memilah dan memroses data pada waktu yang bersamaan. Contoh penggunaan select().
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
Untuk memperjelas berikut adalah contoh program dimana akan menunggu dalam 2.5 detik apakah ada data yang masuk dari inputan keyboard.
/*
** select.c - a select() demo
*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{ struct timeval tv; fd_set readfds;
tv.tv_sec = 2; tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
// don't care about writefds and exceptfds:
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds)) printf("A key was pressed!\n");
else printf("Timed out.\n");
return 0;
}
Contoh penggunaan select() pada alikasi multiperson chat server.
/*
** selectserver.c - a cheezy multiperson chat server */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9034 // port we're listening on
int main(void)
{
fd_set master; // master file descriptor list fd_set read_fds; // temp file descriptor list for select() struct sockaddr_in myaddr; // server address struct sockaddr_in remoteaddr; // client address int fdmax; // maximum file descriptor number int listener; // listening socket descriptor int newfd; // newly accept()ed socket descriptor char buf[256]; // buffer for client data int nbytes;
int yes=1; // for setsockopt() SO_REUSEADDR, below int addrlen; int i, j;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get the listener
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1);
}
// lose the pesky "address already in use" error message
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1);
}
// bind
myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = INADDR_ANY; myaddr.sin_port = htons(PORT); memset(&(myaddr.sin_zero), '\0', 8);
if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) { perror("bind"); exit(1);
}
// listen
if (listen(listener, 10) == -1) { perror("listen"); exit(1);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor fdmax = listener; // so far, it's this one
// main loop for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { perror("select"); exit(1);
}
// run through the existing connections looking for data to read for(i = 0; i <= fdmax; i++) { if (FD_ISSET(i, &read_fds)) { // we got one!! if (i == listener) { // handle new connections addrlen = sizeof(remoteaddr);
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen))
== -1) {
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set if (newfd > fdmax) { // keep track of the maximum fdmax = newfd;
}
printf("selectserver: new connection from %s on socket %d\n", inet_ntoa(remoteaddr.sin_addr), newfd);
}
} else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { // got error or connection closed by client if (nbytes == 0) { // connection closed
printf("selectserver: socket %d hung up\n", i);
} else { perror("recv");
} close(i); // bye!
FD_CLR(i, &master); // remove from master set
} else {
// we got some data from a client for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves if (j != listener && j != i) { if (send(j, buf, nbytes, 0) == -1) { perror("send");
}
}
}
}
}
} // it's SO UGLY!
}
}
} return 0;
}