What is a socket?
A remote-local, application-created/owned, OS-controlled interface to network (a "door")
-> To the kernel, a socket is an endpoint of communication
-> To an application, a socket is a file descriptor
Clients and servers communicate with each by reading from and writing to socket descriptors
socket()
int socket (int family, int type, int protocol)
connect()
int connect (int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
bind()
int bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)
listen()
int listen (int sockfd, int backlog)
accept()
int accept (int sockfd, struct sockaddr cliaddr, socklen_t addrlen)
accept() blocks waiting for a connection request
accept() returns a connected descriptor with the same properties as the listening descriptor
Listening descriptor
-> End point for client connection requests
-> Created once and exists for lifetime of the server
Connected descriptor
-> End point of the connection between client and server
-> A new descriptor is created each time the server accepts a connection request from a client
Why the distinction?
-> concurrent servers that can communicate over many client connections simultaneously
Make file transfer
client.c
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define MAXLINE 80
int main(int argc, char *argv[])
{
int n, cfd, fd, nbytes;
struct hostent *h;
struct sockaddr_in saddr;
char buf[MAXLINE];
char *host = argv[1];
int port = atoi(argv[2]);
if((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("socket() failed.\n");
exit(1);
} //cfd = socket file descriptor
if((h = gethostbyname(host)) == NULL){
printf("Invalid hostname %s\n", host);
exit(2);
}
memset((char *)&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
memcpy((char *)&saddr.sin_addr.s_addr, (char *)h->h_addr, h->h_length);
saddr.sin_port = htons(port); //endian
char *filename = NULL;
size_t size = 0;
getline(&filename, &size, stdin);
filename[strlen(filename) - 1] = '\0';
//get filename
if(connect(cfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
printf("connect() failed.\n");
exit(3);
} //connect
if((fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0666)) < 0){
perror("open");
exit(1);
} //open file
write(cfd, filename, strlen(filename)); //send filename
while((n = read(cfd, buf, MAXLINE)) > 0){
write(fd, buf, n);
}
close(cfd);
close(fd);
return 0;
}
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define MAXLINE 80
int main(int argc, char *argv[])
{
int n, listenfd, connfd, caddrlen, nbytes, fd;
struct hostent *h;
struct sockaddr_in saddr, caddr;
char buf[MAXLINE];
int port = atoi(argv[1]);
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("socket() failed.\n");
exit(1);
} //listen file descriptor (server)
memset((char *)&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(port);
if(bind(listenfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
printf("bind() failed.\n");
exit(2);
}
if(listen(listenfd, 5) < 0){
printf("listen() failed.\n");
exit(3);
}
while(1){
caddrlen = sizeof(caddr);
if((connfd = accept(listenfd, (struct sockaddr *)&caddr, (socklen_t *)&caddrlen)) < 0){
printf("accept() failed.\n");
continue;
} //connfd = connect file descriptor (server - client)
printf("wait connection ...\n");
char filename[10];
nbytes = read(connfd, filename, 10);
printf("Client request %s file!\n", filename);
if((fd = open(filename, O_CREAT|O_RDONLY, 0666)) < 0){
perror("open");
exit(1);
} //open file
while((n = read(fd, buf, MAXLINE)) > 0){
write(connfd, buf, n);
}
close(fd);
close(connfd);
}
}
실행결과, .txt파일 전송은 잘 되는 것 같은데 while문이 무한루프를 도는 것 같다.
-> server쪽에서 socket을 닫아야 while문 빠져나옴