Parent directory
tcp-echo-client.c
tcp-echo-server.c
tcp-recver.c
tcp-sender.c
toupper.c
/*
* tcp-echo-client.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
static void die(const char *s) { perror(s); exit(1); }
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s <server-ip> <server-port>\n",
argv[0]);
exit(1);
}
const char *ip = argv[1];
unsigned short port = atoi(argv[2]);
// Create a socket for TCP connection
int sock; // socket descriptor
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("socket failed");
// Construct a server address structure
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr)); // must zero out the structure
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(ip);
servaddr.sin_port = htons(port); // must be in network byte order
// Establish a TCP connection to the server
if (connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
die("connect failed");
// Read a line from stdin and send it to the server
char buf[100];
if (fgets(buf, sizeof(buf), stdin) == NULL) {
die("fgets returned NULL");
}
size_t len = strlen(buf);
/*
* send(int socket, const void *buffer, size_t length, int flags)
*
* - normally, send() blocks until it sends all bytes requested
* - returns num bytes sent or -1 for error
* - send(sock,buf,len,0) is equivalent to write(sock,buf,len)
*/
if (send(sock, buf, len, 0) != len)
die("send failed");
// Receive the responses from the server and print them
/*
* recv(int socket, void *buffer, size_t length, int flags)
*
* - normally, recv() blocks until it has received at least 1 byte
* - returns num bytes received, 0 if connection closed, -1 if error
* - recv(sock,buf,len,0) is equivalent to read(sock,buf,len)
*/
int r;
while (len > 0 && (r = recv(sock, buf, sizeof(buf), 0)) > 0) {
printf("RECEIVED: [");
fwrite(buf, 1, r, stdout);
printf("]\n");
len -= r;
}
if (r < 0)
die("recv failed");
// Clean-up
close(sock);
return 0;
}
/*
* tcp-echo-server.c
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
static void die(const char *s) { perror(s); exit(1); }
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s <server-port>\n", argv[0]);
exit(1);
}
unsigned short port = atoi(argv[1]);
// Create a listening socket (also called server socket)
int servsock;
if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("socket failed");
// Construct local address structure
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any network interface
servaddr.sin_port = htons(port);
// Bind to the local address
if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
die("bind failed");
// Start listening for incoming connections
if (listen(servsock, 5 /* queue size for connection requests */ ) < 0)
die("listen failed");
int r;
char buf[10];
int clntsock;
socklen_t clntlen;
struct sockaddr_in clntaddr;
while (1) {
// Accept an incoming connection
fprintf(stderr, "waiting for client ... ");
clntlen = sizeof(clntaddr); // initialize the in-out parameter
if ((clntsock = accept(servsock,
(struct sockaddr *) &clntaddr, &clntlen)) < 0)
die("accept failed");
// accept() returned a connected socket (also called client socket)
// and filled in the client's address into clntaddr
fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr));
// Receive msg from client, capitalize the 1st char, send it back
while ((r = recv(clntsock, buf, sizeof(buf), 0)) > 0) {
*buf = toupper(*buf);
if (send(clntsock, buf, r, 0) != r) {
fprintf(stderr, "ERR: send failed\n");
break;
}
}
if (r < 0) {
fprintf(stderr, "ERR: recv failed\n");
}
// Client closed the connection (r==0) or there was an error
// Either way, close the client socket and go back to accept()
close(clntsock);
}
}
/*
* tcp-recver.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
static void die(const char *s) { perror(s); exit(1); }
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s <server-port> <filebase>\n", argv[0]);
exit(1);
}
unsigned short port = atoi(argv[1]);
const char *filebase = argv[2];
// Create a listening socket (also called server socket)
int servsock;
if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("socket failed");
// Construct local address structure
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any network interface
servaddr.sin_port = htons(port);
// Bind to the local address
if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
die("bind failed");
// Start listening for incoming connections
if (listen(servsock, 5 /* queue size for connection requests */ ) < 0)
die("listen failed");
int clntsock;
socklen_t clntlen;
struct sockaddr_in clntaddr;
FILE *fp;
unsigned int filesuffix = 0;
// Variable-length array (VLA) is used here to show that it's legal in C.
// But VLA should be avoided in most cases. The VLA declaration below
// could and should be replaced with heap allocation:
//
// char *filename = malloc(strlen(filebase) + 100);
//
char filename[strlen(filebase) + 100];
int r;
char buf[4096];
uint32_t size, size_net, remaining, limit;
struct stat st;
while (1) {
// Accept an incoming connection
clntlen = sizeof(clntaddr); // initialize the in-out parameter
if ((clntsock = accept(servsock,
(struct sockaddr *) &clntaddr, &clntlen)) < 0)
die("accept failed");
// accept() returned a connected socket (also called client socket)
// and filled in the client's address into clntaddr
fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr));
sprintf(filename, "%s.%u", filebase, filesuffix++);
fprintf(stderr, "file name: %s\n", filename);
if ((fp = fopen(filename, "wb")) == NULL)
die(filename);
// First, receive file size
r = recv(clntsock, &size_net, sizeof(size_net), MSG_WAITALL);
if (r != sizeof(size_net)) {
if (r < 0)
die("recv failed");
else if (r == 0)
die("connection closed prematurely");
else
die("didn't receive uint32");
}
size = ntohl(size_net); // convert it to host byte order
fprintf(stderr, "file size received: %u\n", size);
// Second, receive the file content
remaining = size;
while (remaining > 0) {
limit = remaining > sizeof(buf) ? sizeof(buf) : remaining;
r = recv(clntsock, buf, limit, 0);
if (r < 0)
die("recv failed");
else if (r == 0)
die("connection closed prematurely");
else {
remaining -= r;
if (fwrite(buf, 1, r, fp) != r)
die("fwrite failed");
}
}
assert(remaining == 0);
fclose(fp);
// Third, send the file size back as acknowledgement
stat(filename, &st);
size = st.st_size;
fprintf(stderr, "file size on disk: %u\n\n", size);
size_net = htonl(size);
if (send(clntsock, &size_net, sizeof(size_net), 0)
!= sizeof(size_net))
die("send size failed");
// Finally, close the client connection and go back to accept()
close(clntsock);
}
}
/*
* tcp-sender.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
static void die(const char *s) { perror(s); exit(1); }
int main(int argc, char **argv)
{
if (argc != 4) {
fprintf(stderr, "usage: %s <server-ip> <server-port> <filename>\n",
argv[0]);
exit(1);
}
const char *ip = argv[1];
unsigned short port = atoi(argv[2]);
const char *filename = argv[3];
// Open the file to send
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
die(filename);
// Create a socket for TCP connection
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("socket failed");
// Construct a server address structure
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr)); // must zero out the structure
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(ip);
servaddr.sin_port = htons(port); // must be in network byte order
// Establish a TCP connection to the server
if (connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
die("connect failed");
// First, send file size as 4-byte unsigned int in network byte order
struct stat st;
stat(filename, &st);
uint32_t size = st.st_size;
fprintf(stderr, "file size: %u\n", size);
uint32_t size_net = htonl(size);
/*
* send(int socket, const void *buffer, size_t length, int flags)
*
* - normally, send() blocks until it sends all bytes requested
* - returns num bytes sent or -1 for error
* - send(sock,buf,len,0) is equivalent to write(sock,buf,len)
*/
if (send(sock, &size_net, sizeof(size_net), 0) != sizeof(size_net))
die("send size failed");
// Second, send the file content
char buf[4096];
unsigned int n;
unsigned int total = 0;
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
if (send(sock, buf, n, 0) != n)
die("send content failed");
else
total += n;
}
if (ferror(fp)) {
// fread() returns 0 on EOF or error, so we check if error occurred
die("fread failed");
}
fclose(fp);
fprintf(stderr, "bytes sent: %u\n", total);
// Third, receive file size back from the server as acknowledgement
uint32_t ack, ack_net;
/*
* recv(int socket, void *buffer, size_t length, int flags)
*
* - normally, recv() blocks until it has received at least 1 byte
* - returns num bytes received, 0 if connection closed, -1 if error
* - recv(sock,buf,len,0) is equivalent to read(sock,buf,len)
*
* - With TCP sockets, we can receive less data than we requested;
* MSG_WAITALL flag changes this behavior -- it requests that the
* operation block until the full request is satisfied.
*/
int r = recv(sock, &ack_net, sizeof(ack_net), MSG_WAITALL);
if (r != sizeof(ack_net)) {
if (r < 0)
die("recv failed");
else if (r == 0)
die("connection closed prematurely");
else
die("didn't receive uint32");
}
ack = ntohl(ack_net); // convert it back to host byte order
if (ack != size)
die("ack!=size");
// recv() will return 0 when the server closes the TCP connection
char x;
r = recv(sock, &x, 1, 0);
assert(r == 0);
// Clean-up
close(sock);
return 0;
}
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
char c;
#ifdef STDIO
FILE *fp_in = stdin;
FILE *fp_out = stdout;
while (fread(&c, 1, 1, fp_in) == 1) {
c = toupper(c);
fwrite(&c, 1, 1, fp_out);
}
#endif
#ifdef UNIX
int fd_in = 0;
int fd_out = 1;
while (read(fd_in, &c, 1) == 1) {
c = toupper(c);
write(fd_out, &c, 1);
}
#endif
}