Jump to content

winsock2 troca de dados


seuqram
 Share

Recommended Posts

Pessoal, estou a desenvolver um joguinho multiplayer com o winsock2 e com o opengl.

Fiz uma versão teste do cliente na console aplication e correu tudo bem mas agora estou a ter algumas dificuldades em enquadrar o codigo com o resto do projeto.

Fiz duas funções: a que iniciava o processo todo dos sockets... e outra para atualizar de frame em frame a troca de dados entre servidor/cliente.

O problema é que, pelos vistos, ele só recebe os dados uma vez no inicio e depois para.

As duas funções:

#include "global.h"
char buffer[uLTV+1];
void connect()
{
WSAData wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData)==SOCKET_ERROR)
{
	 printf("error de socket-1!\n");
}

s=socket(AF_INET,SOCK_STREAM,0);
if (s==INVALID_SOCKET) printf("socket e invalido!\n");

sockaddr_in you;
you.sin_family=AF_INET;
you.sin_addr.s_addr=inet_addr("127.0.0.1");// 85.245.61.211 // 192.168.10.2
you.sin_port=htons(20756);

if(connect(s,(LPSOCKADDR)&you,sizeof(you))==-1)
{
	 WSACleanup();
	 printf("conexao falhou!!!\n");
	 system("pause");
}
else
{
u_long iMode=1;
ioctlsocket(s,FIONBIO,&iMode);

buffer[uLTV]=10;
buffer[0]=1;
send(s,buffer,ULTV+1,0);
}
}

void socketshare()
{
if(recv(s,buffer,ULTV+1,0)!=-1)
{
if(buffer[uLTV]==9)
{
buffer[uLTV]=NULL;

float aa,bb,cc;
int jogador;
jogador=atoi((char*)strtok(buffer, "*"));
xxj[jogador]=atof((char*)strtok(NULL, "*"));
yyj[jogador]=atof((char*)strtok(NULL, "*"));
zzj[jogador]=atof((char*)strtok(NULL, "*"));
memset( buffer, NULL, sizeof(buffer));
}}
sprintf(buffer,"%f*%f*%f*",xx,yy,zz);
buffer[uLTV]=8;
send(s,buffer,ULTV+1,0);
memset( buffer, NULL, sizeof(buffer));
}

Função Main:

#include "global.h"

int main(int argc, char **argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(LadoTelax,LadoTelay);
glutCreateWindow("3D World");

//keyboard and mouse func
glutMouseFunc(mousepress);
glutMotionFunc(camaramov);
glutPassiveMotionFunc(camaramov);

// register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glEnable(GL_DEPTH_TEST);

glutKeyboardUpFunc(keyup);
glutKeyboardFunc(keydown);
glutSpecialFunc(keybespecial);
glutSetCursor(GLUT_CURSOR_NONE);

glutTimerFunc(1000, FPS, 1);

connect();

// enter GLUT event processing cycle
glutMainLoop();
return 1;
}

A função connect é que supostamente inicia, a sockeshare a que troca os dados... esta é chamada pela função renderscreen para ser atualizada de frame em frame.

Se conseguirem ver algum erro que me está a escapar ficaria muito agradecido 😛

Desde já obrigado.

Edited by apocsantos
geshi
Link to comment
Share on other sites

Bom dia,

Quando executado 2 vezes o cliente, o primeiro não apanha as coordenadas da posição do jogador do segundo.

O segundo vê apanha apenas uma vez, no inicio ,as coordenadas do primeiro ficando o boneco parado sem modificar a sua posição.

Executando mais, vêem-se todos os outros anteriores parados sem movimento.

Edited by seuqram
Link to comment
Share on other sites

Aplicacoes web.cliente/servidor sao como ter duas maos a bater palmas. Necessitas da mao direita e da esquerda.

O problema e que apresentas o codigo de uma das maos

PS desconfio que o problema esta no modelo bloqueante das chamadas, mas sem mais informacao e dificil dizer-lo con certeza

Edited by HappyHippyHippo
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

É verdade Happy.

O problema disto, eu acho, é que está em TCP, logo como envia de frame a frame as cordenadas e recebe muito mais devagar, os bonecos parecem parados.

Estarei eu enganado?

Andei a pesquisar e parece que para fazer uma conexao por UDP tenho que trocar os "send" por "sendto" e os "recv" por "recvfrom" e no server em vez de: me.sin_addr.s_addr=htonl(SOCK_STREAM); meter: me.sin_addr.s_addr=htonl(SOCK_DGRAM);

Aqui está o codigo do servidor:

#include<winsock2.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_PLAYERS 30
#define MAX_ROOMS 1
#define ULTV 39
char nome[MAX_PLAYERS][15];
char getbuffer[uLTV+1];
char *buffer;
char buffer2[15];
int quartosn=0;
int playerstatus[MAX_PLAYERS];
char playerxyz[MAX_PLAYERS][35];
int main()
{

WSAData wsaData;
 if(WSAStartup(MAKEWORD(2,2),&wsaData)==SOCKET_ERROR)
{
	 printf("error de socket-1!\n");
	 return 0;
}

sockaddr_in me;
sockaddr you[2];
me.sin_family=AF_INET;
me.sin_addr.s_addr=htonl(SOCK_STREAM);
me.sin_port=htons(20756);

int s;
s=socket(AF_INET,SOCK_DGRAM,0);
if (s==INVALID_SOCKET) printf("socket e invalido!\n");

if(bind(s,(LPSOCKADDR)&me,sizeof(me))==-1){printf("erro ao abrir porta!\n");system("pause");return 1;}

if(listen(s,1)==-1)
{
	 printf("ERROR a fazer listen!\n");
	 system("pause");
	 return 1;
}
int new_s[MAX_PLAYERS];
int quantos=0;
int quantosv,quantosv2;

int addr_size = sizeof (sockaddr);
u_long iMode=1;
ioctlsocket(s,FIONBIO,&iMode);

//Instruções do servidor
while(1)
{
new_s[quantos]=accept(s,NULL,NULL);
if(new_s[quantos]!=INVALID_SOCKET){quantos++;}
quantosv=-1;
while(quantosv<quantos-1)
{
 quantosv++;
 if(recv(new_s[quantosv],getbuffer,ULTV+1,0)!=-1)
{
if(getbuffer[uLTV]==1){FILE*User; buffer=(char*)strtok(getbuffer, "-"); User=fopen(buffer,"r");if(User!=NULL){memset( getbuffer, NULL, sizeof(getbuffer));getbuffer[uLTV]=2;send(new_s[quantosv],getbuffer,ULTV+1,0);}else {printf("%s foi registado\n",buffer);User=fopen(buffer,"w");buffer=(char*)strtok(NULL, "-");fwrite(buffer,sizeof(char),15,User);fclose(User);memset(getbuffer,NULL,sizeof(getbuffer));getbuffer[uLTV]=3;send(new_s[quantosv],getbuffer,ULTV+1,0);}}								
if(getbuffer[uLTV]==4){FILE*User; buffer=(char*)strtok(getbuffer, "-"); User=fopen(buffer,"r");if(User!=NULL){buffer=(char*)strtok(NULL, "-");fread(buffer2,sizeof(char),15,User);printf("%s",buffer);if(strcmp (buffer, buffer2) == 0){memset( getbuffer, NULL, sizeof(getbuffer));getbuffer[uLTV]=5;send(new_s[quantosv],getbuffer,ULTV+1,0);}else{memset( getbuffer, NULL, sizeof(getbuffer));getbuffer[uLTV]=6;send(new_s[quantosv],getbuffer,ULTV+1,0);}}else {memset( getbuffer, NULL, sizeof(getbuffer));getbuffer[uLTV]=6;send(new_s[quantosv],getbuffer,ULTV+1,0);}fclose(User);}								
if(getbuffer[uLTV]==7){quartosn++;}
if(getbuffer[uLTV]==8){memset( playerxyz[quantosv], NULL, sizeof(playerxyz[quantosv]));getbuffer[uLTV]=NULL;sprintf(playerxyz[quantosv],"%s",getbuffer);memset( getbuffer, NULL, sizeof(getbuffer));}
if(getbuffer[uLTV]==10){playerstatus[quantosv]=getbuffer[0];getbuffer[0]==NULL;}
getbuffer[uLTV]=NULL;
}
if(playerstatus[quantosv]!=0)
{
quantosv2=-1;
while(quantosv2<quantos-1)
{
quantosv2++;
if(quantosv2!=quantosv&&playerstatus[quantosv]==playerstatus[quantosv2])
{
 sprintf(getbuffer,"%d*%s",quantosv,playerxyz[quantosv]);
 getbuffer[uLTV]=9;
 send(new_s[quantosv2],getbuffer,ULTV+1,0);
 printf("%s\n",buffer);
 memset( getbuffer, NULL, sizeof(getbuffer));
}
}
}
}
}
}

//getbuffer[uLTV]==
//1-Chama o servidor para um Registro
//2-Registo não aceite
//3-Registo aceite
//4-Pede ao servidor para logar
//5-Logou com sucesso
//6-Falhou a logar
//7-Criar quarto
//8-O server recebe as cordenadas dos jogadores
//9-O server envia as cordenadas dos jogadores
//10-Jogador entra num quarto

O que é que me aconcelha fazer?

Edited by apocsantos
geshi
Link to comment
Share on other sites

como estava à espera.

o teu problema é que o teu servidor está parado nesta instrução:

new_s[quantos]=accept(s,NULL,NULL);

o que quero dizer, é que enquanto o servidor não receber uma nova ligação, nunca irá retransmitir os dados para os clientes.

se pretendes esse modelo de cliente/servidor, terás de ter no servidor dois threads, um para receber novas ligações e outro para fazer o broadcast das mensagens.

existem outros modelos como o P2P, mas parece que necessitas de exercítar o teu código de rede primeiro

  • Vote 1
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Esse podia ser muito bem o problema. Como eu disse anteriormente eu fiz um teste no console aplication e dá para entender que o cliente está sempre a receber dados. Metento um printf no meio do loop do server ve-se que ele não para aí nessa instrução...

O modelo que voce falou (P2P) ainda acho desnecessário pois ainda estou num grande começo do projeto.

Edited by seuqram
Link to comment
Share on other sites

ok, já vi que tens ai o código para tornar o accept não bloquante.

o teu código nºao só está incompreensívelmente mal estruturado como nem sequer está bem formatado, o que torna todo o processo de ler/interpretar o que tens muito complicado.

devido a essa situação, entquanto não apresentares (pelo menos) o código bem indentado assim como toda a informação relevante (como o que raio é e para que serve o valor ULTV) não poderei ajudar mais

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Desculpe lá...

O codigo, sim está bem estruturado mas quando meto aqui no forum fica um bocadinho distorcido :S

O ULTV é o ultimo valor da lista de variaveis getbuffer

O valor ULTV+1 é o valor que vai determinar o tamanho da variavel getbuffer, por exemplo: getbuffer[40] ULTV=39

Este por sua vez (o ultimo valor da lista) é o que vai "explicar" do que se trata o conjunto de dados recebidos ou pelo cliente ou servidor.

O "quantos" é a variavel do numero de clientes conectados.

O "quantosv" é a variavel que percorre do 0 ao valor quantos para verificar o estado de dados de todas as conecções.

O "quantosv2" é a variavel que percorre tambem todos esses numeros que serve para determinar a quem o programa deve enviar as cordenadas do [quantosv] jogador.

O buffer é um ponteiro para dar auxilio ao getbuffer, este é o que será enviado/recebido.

Eu penso que o server está corretamente logico. O problema ou está nas más definidas funções do client ou mesmo na ligação, que é TCP.

Obrigado por abdicar do seu tempo.

Edited by seuqram
Link to comment
Share on other sites

então vamos fazer assim

em vez de estar a tentar ler um código todo desformatado, e tentar adivinhar o que não foi apresentado, coloca todo o teu código disponível em algum serviço online (tipo dropbox ou algo do género) para se poder ver e talvez testar

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

http://s000.tinyupload.com/index.php?file_id=08216118522950980374

Podes movimentar a camara com os butoes wasd, saltar com o space, por blocos com o botao lado direito do rato e tiralos com o esquerdo.

Diverte-te 😛

ps:eu não sei se para rodar o executável precisa do dll do opengl glut.

Edited by seuqram
Link to comment
Share on other sites

Como eu disse, o problema era de ser em TPC trocando na função do cliente:

void socketshare()
{
if(recv(s,buffer,ULTV+1,0)!=-1)
{
if(buffer[ULTV]==9)
{
buffer[ULTV]=NULL;
float aa,bb,cc;
int jogador;
jogador=atoi((char*)strtok(buffer, "*"));
xxj[jogador]=atof((char*)strtok(NULL, "*"));
yyj[jogador]=atof((char*)strtok(NULL, "*"));
zzj[jogador]=atof((char*)strtok(NULL, "*"));
memset( buffer, NULL, sizeof(buffer));
}}
sprintf(buffer,"%f*%f*%f*",xx,yy,zz);
buffer[ULTV]=8;
send(s,buffer,ULTV+1,0);
memset( buffer, NULL, sizeof(buffer));
}
if(recv(s,buffer,ULTV+1,0)!=-1)-> while(recv(s,buffer,ULTV+1,0)!=-1)

Assim ele recebe todos os dados que estão á espera de serem recebidos pela aplicação.

Sabem, para fazer DNS dinamic, se preciso apenas de trocar o ip no client pelo nome do host?

Link to comment
Share on other sites

sim eu sei. Mesmo por isso, como está em TCP tenho que meter o while para que ele leia os pacotes antigos e novos e não se atrase em relação ao servidor.

em UDP eu acho que iria ser muito trabalhoso pois tinha que fazer outras funções para verificar se os pacotes tinham sido enviados e se não, reenvia-los...

Apesar disso, quando eu testei o jogo com uns amigos meus, alguns dados foram perdidos :/

como por exemplo, eu no meu cliente metia um bloco, e por vezes no dele não aparecia a mudança...

Edited by seuqram
Link to comment
Share on other sites

hehe ... não há nada como meter as mão na massa para aprender em primeira mão os problemas de uma escolha.

agora só falta esperimentares com jogadores de outro continente para perceber o porquê da escolha de UDP por parte de muita gente ...

ou então ter um jogo em que a necessitade de o tempo de resposta seja mais exigente

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

UDP é por sí só um protocolo onde se espera perdas de pacotes.

quando testas localmente, a probsbilidade de perdas de pacotes é extremamente baixa.

ao contrário do envio para o exterior onde o mesmo pacote necessita de viajar por imensos dispositivos que poderão eventualmente descartar o pacote devido a limites de buffer.

(sim, routers ignoram pacotes para evitar buffer overflow)

é por isso que para aplicações que não satisfacam as seguintes duas condições, o TCP é usado:

- necessidade de tempo de processamento rápido (real time processing)

- capacidade de recuperar de falhas/perdas de envio

isto porque a maior parte do TCP, não é mais do que um processo de verificação e recuperação dessas mesmas falhas completamente transparente para as aplicações acima da stack

  • Vote 1
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Ok obrigado. Mesmo sendo em TCP, se houver um subcarga de pacotes, parte dos mesmos podem-se perder?

sim ... ele perdem-se, mas o protocolo recupera-os por ti, não dás conta do processo.

no entanto, tens de ter em conta que esse processo de verificação/recuperação é algo que atrasa a comunicação.

não podes supor que um pacote recebido foi acabadinho de ser criado no computador que o enviou.

  • Vote 1
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Sabem, para fazer DNS dinamic, se preciso apenas de trocar o ip no client pelo nome do host?

e mais uma coisa se não se importar de responder 😛

se um pacote mais pequeno for enviado de um ponto ao outro e esse ponto final estiver preparado para receber pacotes de maiores dimensões, o pacote é negado?

exemplo:

send(new_s[quantosv],getbuffer,10);

recv(s,getbuffer,30);

Edited by seuqram
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.