Я действительно новичок в сокетах, и большая часть кода написана на основе фрагментов кода и советов из других потоков и их ответов, так что это может быть трудно читать.
ЭтоВ частности, поток был тем, из которого я брал большую часть кода.
Мое назначение состоит в создании приложения, способного подключаться к серверу, а также отправлять и получать сообщения и файлы другим подключенным к нему клиентам,По сути, каждая машина работает как клиент и сервер одновременно, имея возможность отправлять и получать пакеты, пока они подключены к серверу.
Я уже могу отправлять и получать сообщения(строки), однако, я пока не могу отправлять или получать файлы, и, честно говоря, я понятия не имею, как это сделать, так как нам было мало объяснено о сокетах до того, как мне дали это назначение.
На всякий случай сокеты ДОЛЖНЫ быть UDP .Я не могу использовать TCP в этом случае.
Вот код:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <sys/socket.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h> // para inet_Addr, etc
#include <netdb.h> // estructuras
#include <sys/signal.h>
#include <ctype.h>
#include <openssl/md5.h>
#include "PB.h"
#include <fcntl.h>
#include <ctime>
#include <iomanip>
#define MAX_LARGO_IP 16
#define MAX_USPW 25
#define MAX_LARGO_MENSAJE 255
#define MAX_NOMBRE_ARCHIVO 20
#define MAX_LARGO_ARCHIVO 65535
#define BUFLEN 503
int fd1;
using namespace std;
void printProgress (double percentage);
unsigned long fsize(char* file)
{
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(f);
fclose(f);
return len;
}
int main(int argc, char * argv[]){
if (argc < 4)
{
cout << "\33[46m\33[31m[ERROR]:" << " Faltan argumentos: port, ipAuth, portAuth.\33[00m\n";
exit (1);
}
// Signal handler
// *********************************
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &manejadorSenhales;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGKILL, &sa, NULL);
signal(SIGALRM, SIG_IGN);
// **********************************
cout << "\33[34mRedes de Computadoras 2018\33[39m: Sistema de Mensajeria.\nEscuchando en el puerto " << argv[1] << ".\nProceso de pid: " << getpid() << ".\n";
char * user = new(char[MAX_USPW]);
char * pass = new(char[MAX_LARGO_MENSAJE]);
char * buf = new(char[MAX_LARGO_MENSAJE]);
char * msjAnterior = new(char[MAX_LARGO_MENSAJE]);
char * mensaje = new(char[MAX_LARGO_MENSAJE]);
cout << "Usuario: ";
cin >> user;
cout << "Clave: ";
cin >> pass;
strcpy(mensaje, user);
strcat(mensaje, "-");
///////////////////
// AUTENTICATION // THIS PART CONNECTS YOU TO THE SERVER //////////////////////////////
///////////////////
int numbytes;
unsigned long ultimoRemitente = 0;
strcpy(msjAnterior, "\0"); //inicializo el buffer como vacio
fd1 = socket(AF_INET, SOCK_STREAM, 0);
if (fd1 < 0){
cout << "ERROR: socket()\n";
exit (0);
}
struct hostent *he;
struct sockaddr_in server;
socklen_t longitudServer = sizeof(server);
if ((he=gethostbyname(argv[2]))==NULL){
printf("ERROR: gethostbyname()\n");
exit(0);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[3]));
server.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(server.sin_zero),8);
if(connect(fd1, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){
printf("ERROR: connect()\n");
exit(0);
}
if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){
printf("ERROR: recv()\n");
exit(0);
}
buf[numbytes-2]='\0';
if (strcmp(buf, "Redes 2019 - Obligatorio 2 - Autenticacion de Usuarios") != 0){
printf("ERROR: protocolo incorrecto()\n");
exit(0);
}
mensaje[strlen(mensaje) + 1] = '\n';
mensaje[strlen(mensaje)] = '\r';
send(fd1, mensaje, strlen(mensaje),0);
if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){
printf("ERROR: recv()\n");
exit(0);
}
buf[numbytes-2]='\0';
if (strcmp(buf, "NO") == 0){
printf("ERROR: Autenticacion Incorrecta.\n");
exit(0);
}
if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){
printf("ERROR: recv()\n");
exit(0);
}
buf[numbytes-2]='\0';
struct sockaddr_in cliente;
socklen_t largoCliente = sizeof(cliente);
// ALL OF THIS IS USED TO SHOW DATE AND TIME OF EACH MESSAGE
time_t timer, timerNew;
tm fechaActual, fechaNew;
time(&timer);
fechaActual=*(localtime(&timer));
int archivo, n;
cout << "Bienvenido " << buf << endl;
close (fd1);
int pid = fork();
if (pid < 0){
cout << "\33[46m\33[31m[ERROR]:" << " Imposible bifurcar.\33[00m\n";
exit(0);
}
if (pid > 0){
/////////////////
// SERVER SIDE // WHERE MESSAGES AND FILES ARE RECEIVED ///////////////
/////////////////
printf("\33[34mRx\33[39m: Iniciada parte que recepciona mensajes. Pid %d\n", getpid());
char ipOrigen[MAX_LARGO_IP];
unsigned int fd_rx;
char fname[MAX_NOMBRE_ARCHIVO];
char flen[20];
char messagef[BUFLEN];
FILE *fp;
fd_rx = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd_rx < 0){
cout << "ERROR: socket()\n";
exit (0);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
server.sin_addr.s_addr = INADDR_ANY;
bzero(&(server.sin_zero),8);
if(bind(fd_rx,(struct sockaddr*)&server, sizeof(struct sockaddr))){
cout << "ERROR: bind()\n";
exit (0);
}
while (true)
{
//sleep(3);
if(recvfrom(fd_rx, buf, MAX_LARGO_MENSAJE, 0, (struct sockaddr *)&cliente, &largoCliente) == -1) // Si da error, poner sizeof(server) o &longitudServer
printf("ERROR: 1 recvfrom()\n");
else
{
time(&timerNew);
fechaNew=*(localtime(&timerNew));
// MAKES SURE A MESSAGE ISN'T SENT TWICE IN A SHORT AMOUNT OF TIME
if((strcmp(msjAnterior,buf) != 0) || (fechaNew.tm_sec > fechaActual.tm_sec ) || (ultimoRemitente != cliente.sin_addr.s_addr))
{
time(&timer);
fechaActual=*(localtime(&timer));
cout << setfill('0');
cout << "[" << fechaActual.tm_year + 1900 << "." << setw(2) << fechaActual.tm_mon + 1 << "." << setw(2) << fechaActual.tm_mday
<< " " << setw(2) << fechaActual.tm_hour << ":" << setw(2) << fechaActual.tm_min << "] " ; // SHOWS DATE AND TIME
strcpy(ipOrigen, inet_ntoa(cliente.sin_addr));
if(strcmp(buf, "peer_discover")==0)
cout << "envio de peer discover" << endl;
else if (strcmp(buf, "enviar") == 0)
{
///////////////////////////////////////////////////////////////
////// THIS IS WHERE THE FILE TRANSFER PART STARTS ////////////
///////////////////////////////////////////////////////////////
if(recvfrom(fd_rx, messagef, 20, 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
printf("ERROR: 2 recvfrom()\n");
memset(messagef, 0, 503);
if(recvfrom(fd_rx, messagef, 20, 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
printf("ERROR: 3 recvfrom()\n");
strcpy(flen, messagef);
unsigned long mm = atoi(messagef);
fp = fopen(flen, "wb");
int itr=1;
memset(messagef, 0, 503);
while(itr*503 < mm)
{
if(recvfrom(fd_rx, messagef, 503, 0, (struct sockaddr *)&cliente, &largoCliente) == -1){
printf("ERROR: 4 recvfrom()\n");
exit(0);
}
fwrite(messagef, 503, 1, fp);
memset(messagef, 0, 503);
itr++;
}
if (recvfrom(fd_rx, messagef, (mm % 503), 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
printf("ERROR: 5 recvfrom()\n");
fwrite(messagef, (mm % 503), 1, fp);
memset(messagef, 0, 503);
fclose(fp);
}
///////////////////////////////////////////
////// FILE TRANSFER PART ENDS ////////////
///////////////////////////////////////////
else
cout << ipOrigen << " " << buf << endl;
strcpy(msjAnterior, buf);
ultimoRemitente = cliente.sin_addr.s_addr;
strcpy(buf, "\0");
}
}
}
}
else if (pid == 0)
{
////////////////////
// CLIENT SIDE ///// WHERE MESSAGES AND FILES ARE SENT FROM ////////////////
////////////////////
printf("\33[34mTx\33[39m: Iniciada parte que transmite mensajes. Pid %d\n", getpid());
char ipDestino[MAX_LARGO_IP];
char buffS[MAX_LARGO_MENSAJE + 1];
char message[MAX_LARGO_MENSAJE];
char * enviar = new(char[7]);
strcpy(enviar, "enviar");
char fname[BUFLEN];
unsigned long siz;
char str[10];
FILE *f;
int enviados = 0;
unsigned int fd_tx;
fd_tx = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd_tx < 0){
cout << "ERROR: socket()\n";
exit (0);
}
while (true)
{
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
bzero(&(server.sin_zero),8);
cin >> ipDestino;
if (ipDestino[0] == '*'){
int broadcastPermission = 1;
if (setsockopt(fd_tx, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission,sizeof(broadcastPermission)) < 0){
fprintf(stderr, "setsockopt error");
exit(1);
}
}
else if(ipDestino[0] == '&')
cout << "Se hace peer_discover" << endl;
else if ((he=gethostbyname(ipDestino))==NULL){
printf("ERROR: gethostbyname()\n");
exit(0);
}
server.sin_addr = *((struct in_addr *)he->h_addr);
cin.ignore(1,' ');
cin.getline(buffS,MAX_LARGO_MENSAJE,'\n');
printf("ipDestino: %s, mensaje: %s \n", ipDestino, buffS);
if (buffS[0] == '&')
{
///////////////////////////////////////////////////////////////
////// THIS IS WHERE THE FILE TRANSFER PART STARTS ////////////
///////////////////////////////////////////////////////////////
cout << "\nSE QUIERE MANDAR ARCHIVO\n";
sendto(fd_tx, enviar, sizeof(char), 0, (struct sockaddr *)& server, sizeof(server));
cout << "\nSE MANDO NOMBRE ARCHIVO\n";
int i = 8;
int j = 0;
while (buffS[i] != '\n'){
fname[j++] = buffS[i++];
}
cout << "nombre archivo: " << fname << endl; // muestra el nombre para saber si esta bien. ELIMINAR
sleep(1);
sendto(fd_tx, fname, 20, 0, (struct sockaddr *)&server, sizeof(server));
siz = fsize(fname);
sprintf(str, "%d", siz);
sendto(fd_tx, str, 20, 0, (struct sockaddr *)&server, sizeof(server));
f = fopen(fname, "rb");
memset(message, 0, 503);
fread(message, 503, 1, f);
int itr = 1;
while(itr*503 < siz)
{
if(sendto(fd_tx, message, 503, 0, (struct sockaddr*)&server, sizeof(server)) == -1){
cout << "ERROR: 1 send()\n";
exit(0);
}
memset(message, 0, 503);
fread(message, 503, 1, f);
itr++;
}
fread(message, (siz % 503), 1, f);
if(sendto(fd_tx, message, (siz % 503), 0, (struct sockaddr*)&server, sizeof(server)) == -1){
cout << "ERROR: 2 send()\n";
exit(0);
}
fclose(f);
}
///////////////////////////////////////////
////// FILE TRANSFER PART ENDS ////////////
///////////////////////////////////////////
else{
// SEND MESSAGES
enviados = sendto (fd_tx, buffS, sizeof(char) * (strlen(buffS) + 1), 0, (struct sockaddr *)&server, sizeof(server));
if(enviados != -1)
cout << enviados << "bytes enviados.\n" ;
else
cout << "No se pudo enviar el mensaje.\n";
}
}
}
}
Извините.Это действительно долго, поскольку и серверная, и клиентская стороны должны находиться в одном и том же файле.
При попытке отправить файл программа возвращает «нарушение сегмента» SIGSEGV во втором cout, после snedto.
cout << "\nSE QUIERE MANDAR ARCHIVO\n";
sendto(fd_tx, enviar, sizeof(char), 0, (struct sockaddr *)& server, sizeof(server));
cout << "\nSE MANDO NOMBRE ARCHIVO\n"; <--- RIGHT HERE
Полагаю, что-то не так с серверной стороной, но я понятия не имею, что именно это может быть.
Любая помощь будет принята с благодарностью.