Sockets

ewillwin·2022년 6월 2일
0

System Programming Lab

목록 보기
11/15
post-thumbnail

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)

  • socket() creates a socket descriptor
  • family specifies the protocal family
  • type specifies the communication semantics
  • protocol sepcifies a particular protocol to be used with the socket

connect()
int connect (int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)

  • Used by a TCP client to establish a connection with a TCP server
  • servaddr contains <IP address, port number> of the server
  • The client does not have to call bind() before calling connect()
  • Client process suspends (blocks) until the connection is created

bind()
int bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)

  • bind() gives the socket sockfd the local address addr
  • addr is addrlen bytes long

listen()
int listen (int sockfd, int backlog)

  • listen() converts an unconnected socket into a passive socket, indicating that the kernel should accept incoming connection request
    -> When a socket is created, it is assumed to be an active socket, that is, a client socket that will issue a connect()

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

  • The server runs in the foreground and The client runs in the foreground
  • When the name of the file is entered at client-side, client send filename to server
  • If server received the file name, reads the file and sends it to the client.
  • After server send the target file to client, server quit the connection and wait next connect. (Server will not quit before input "crtl + c" in 1st terminal)
  • After client receive the target file from server, save it and quit the process.
  • The length of file name is shorter than 80 bytes.

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문 빠져나옴

profile
💼 Software Engineer @ LG Electronics | 🎓 SungKyunKwan Univ. CSE

0개의 댓글