C # protocolo cliente-servidor / pergunta modelo

votos
2

Eu estou tentando trabalhar conceitualmente através de um modelo para um aplicativo de soquete de cliente-servidor que estou escrevendo em c # (cliente e servidor). Meu servidor terá que lidar com muitos clientes de uma só vez, e de preferência várias solicitações de um cliente ao mesmo tempo. Eu tenho trabalhado para fora um recipiente para minha comunicação onde vou enviar um cabeçalho de comprimento fixo no início de cada mensagem que irá conter (entre outras coisas) o comprimento da mensagem. Tenho alguma experiência com programação de socket em c #, por isso estou confortável usando soquetes assíncronos.

A principal coisa que eu estou tendo problemas com, conceitualmente, é preciso tanto o cliente e servidor para ser capaz de receber mensagens a qualquer momento. O cliente irá estabelecer uma conexão, e manter-se logado (como um cliente de mensagens instantâneas), e ele terá de tanto receber dados por vezes arbitrárias e fazer pedidos às vezes arbitrárias. Eu também queria, como parte do meu protocolo, para receber uma resposta a cada solicitação feita (seja a partir do servidor para o cliente, ou cliente para o servidor).

Eu gostaria de ser capaz de usar um único soquete, se possível. Eu acredito que eu poderia fazer este trabalho utilizando dois soquetes, um para fazer servidor-> solicitações do cliente e um para client-> solicitações do servidor, mas eu não quero que as complicações extras de lidar com duas portas / conexões. No entanto, usando uma única tomada, não estou certo de como gerenciar o envio de pedidos e obter respostas quando eles poderiam ser intercaladas.

Não consigo encontrar qualquer exemplo de um servidor similar ou cliente em minha busca. Graças a quem oferece quaisquer ides.

Publicado 19/05/2009 em 22:38
fonte usuário
Em outras línguas...                            


2 respostas

votos
3

Sockets são bidirecionais. Você só precisa de um soquete para enviar dados e para trás entre dois pontos finais. Mas no cliente, você provavelmente precisará ter um segmento em constante leitura da tomada e notificar algum componente ou na fila os dados que recebe assim que é processado em outros lugares, enquanto outra thread está a enviar dados através do mesmo socket. Desta forma, você ter uma comunicação assíncrona.

Mas no lado do servidor que você precisa para abrir um ServerSocket que irá ligar a uma porta TCP e aceitar conexões nessa porta; cada conexão você aceitar é um novo Socket. Então você tem uma tomada por cliente, e você provavelmente precisará de um thread por cliente.

Você precisa estabelecer um protocolo para as mensagens que você estará passando por soquete. Você pode preparar o seu próprio protocolo ou olhar um para cima, dependendo do que você quer fazer. Normalmente você vai primeiro enviar dois ou quatro bytes com o comprimento para o resto da mensagem, para que o outro lado sabe ler que muitos bytes do fluxo; essa é uma mensagem. O início da mensagem é geralmente o tipo de mensagem; em um cenário muito simples, você pode dizer que um "1" é uma solicitação do cliente, um "2" é uma resposta do servidor, um "3" é um eco do cliente, "4" é o servidor de resposta de eco, "5" é servidor echo "6" é cliente resposta de eco, etc. Dessa forma, você recebe uma mensagem, analisá-lo e, em seguida, você sabe que é um pedido de um cliente ou uma resposta a uma mensagem enviada a partir do servidor, por exemplo.

Respondeu 19/05/2009 em 23:50
fonte usuário

votos
2

Se você estiver usando TCP, então você terá necessariamente de ter uma tomada por cliente no lado do servidor, bem como a tomada para atender as ligações. Para UDP você pode fazer isso tudo com um único soquete. Independentemente disso, faça o seguinte para qualquer um o seu um socket UDP, ou para cada soquete cliente TCP:

Ter um BeginReceiveir em todos os momentos e BeginWritequando o evento ocorre necessário (ou seja, o usuário pressiona um botão ou uma mensagem veio em que você precisa fazer algo a respeito).

EDIT: Em resposta ao seu comentário, a maneira que eu lidar com isso seria incluir um ID do pedido em seu cabeçalho. Sempre que enviar um pedido (de cada extremidade) incluir um valor único para essa mensagem. Usar um Dictionary<RequestId, RequestState>(com substituições apropriadas para os tipos) e ver se uma mensagem recebida se refere a um pedido de pré-existente. Além disso, você pode especificar que todas as identificações com o conjunto de bits elevada são pedidos originários no cliente e IDs com o alto bit apuradas são do servidor para evitar colisões:

Server                      Client
Request 0x00 -------------> Starts processing

Starts processing <-------  (unrelated) Request 0x80

Request 0x00 complete <---- Sends response to 0x00

Sends response to 0x80 ---> Request 0x80 complete

Este é o sistema que o protocolo OSCAR da AOL usa para (possivelmente lentas) pedidos stateful.

EDIT2: Hm, ok ... você realmente deseja bloquear nele? Algo que você pode fazer é ter um segmento separado lidar com os Send/ Receiveas chamadas. Esta discussão se comunicar com o segmento principal via uma fila thread-safe "enviar mensagem" e um similar "mensagem recebida" pseudo-fila. A razão de eu chamar o último um pseudo-fila é que você iria querer a capacidade de receber mensagens fora de ordem da fila. O thread principal iria colocar uma mensagem na fila de envio, em seguida, bloquear na fila de recebimento. Cada vez que o fio de tomada atualiza a fila de recebimento, o segmento principal iria acordar e verificar se a mensagem que ele quer é lá ainda. Se for, ele iria levá-la (de ordem) e terminar a operação desejada. Se a mensagem não está lá ainda, ele tinha acabado de bloquear na fila novamente. Quando a operação é finalmente concluído que havia acabado de retomar a operação normal e receber mensagens, a fim da fila de recebimento e processá-los ou fazer qualquer outra coisa que ele faz.

Isso faz algum sentido? Sinto muito se ele é meio confuso ...

Respondeu 19/05/2009 em 22:41
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more