Pues de igual manera.
haces un lstat para que sepas del archivo que se trata y puedas darle una extensión, el tamaño, ...
El que envia:
1- abre el fichero y lee un bloque de bytes
2- lo envia por el socket
3- puedes indicar cual es el ultimo pakete con un campo extra en una estructura. Que será cuando encontremos final de fichero
El que recibe:
1- abre un fichero en modo escritura
2- lee del socket mientras le sigan llegando paketes y los escribe en el fichero abierto
3- ya está todo.

Un sencillo ejemplo:
void recibe_file(FILE * fd, int sock) {
PACKET *packet; // puntero a la estructura del protocolo del paquete
int i; // contador de caracteres
packet = (PACKET *) malloc (sizeof(*packet)); //inicializamos el puntero
printf("Recibiendo archivo\n");
do
{
lee_paquete(packet, sock); //esto es recv
/* Ordenamos los bytes de red a orden de bytes de host */
if (ntohl(packet->control) != DATOS)
ERROR("TIPO DE PAQUETE INESPERADO\n");
for (i=0;i < ntohl(packet->size); i++)
putc (packet->data[i], fd);
} while (!ntohl(packet->last));
printf("Archivo recibido\n");
} // fin funcion
Para enviar:
void carga_paquete(FILE *fd,PACKET *packet){
int i=0; // contador de bytes
char c; //variable donde se almacena el caracter leido
while(i<SIZE){ // mientras no se llege al limite de bytes de datos ...
c=getc(fd); // leemos del fichero un caracter
if(feof(fd)) break; //si llegamos al final del fichero salimos del bucle
packet->data[i++]=c; //guardamos los bytes leidos en el campo data
}//fin while
packet->size=htonl(i); //convertimos el numero de bytes que enviaremos a formato red
if (feof(fd))
packet->last=htonl(1); //convertimos la ordenacion de bytes del host a la de red
else
packet->last=htonl(0);
packet->control = htonl(DATOS);
}
void check(PACKET* packet){
char* ptr = (char*) packet; // localizamos secuencia de 32 bits en el paquete
int i;
int sum=0;
packet->check=0;
for (i=0; i<sizeof(*packet)-4;i++)
sum += *ptr++; //acumulamos el numero de bits
packet->check = htonl(sum); // ordenamos los bits para enviarlos por la red
} //fin check
void envia_archivo(int sc, char *archivo){
FILE *df;
PACKET *packet;
int cont=0,vivo=1;;
packet = (PACKET *) malloc (sizeof *packet); //inicializamos el puntero
df=openfile(archivo); //abrimos el archivo que nos piden
printf("Se está procediendo a enviar el archivo %s\n",archivo);
do{
carga_paquete(df,packet); // cargamos la informacion sobre el archivo
packet->secuencia = htonl(cont++); // numero de paquete
check(packet); // hacemos la suma de comprobacion
envia_paquete(sc,packet); //es un send
}while(!df && vivo); // lo hacemos mientras existan bytes que leer y recibamos el ping
free(packet); // liberamos la memoria
} // fin envia_archivo
La estructura puede ser algo asi, aunque esto es muy variable:
typedef struct
{
tipopakete control; // tipo de pakete
int secuencia; // secuencuencia de pakete
int size; // catidad de datos ( en bytes)
int last; // indicador del ultimo pakete
char data[SIZE]; // datos
int check; // detecta los errores(checksum)
} PACKET;
Saludos
PD: Solo es una referencia, es parte del codigo de un pekeño ftp que tuve que hacer años atrás cuando mis conocimientos eran menores.