Visão geral do processo básico de programação
Para realizar a comunicação entre o cliente e o servidor, o cliente e o servidor precisam ser concluídos juntos. Dentre eles, o processo de programação do servidor TCP e do cliente é mostrado na figura:
primeiro, o servidor cria um soquete, em seguida, vincula a porta de comunicação e cria uma fila de escuta. Depois disso, iniciou-se o processo de comunicação. Nesse momento, o servidor é bloqueado na aceitação até que o cliente tcp tome a iniciativa de se conectar para um handshake de três vias para estabelecer uma conexão. Nesse momento, a função de gravação do cliente envia uma solicitação ao servidor, e o servidor lê para ler a solicitação e processá-la. Após a conclusão do processamento, a função de gravação do servidor é chamada para enviar uma mensagem de resposta ao cliente, e o cliente recebe a mensagem de resposta por meio de leitura. Nesse ponto, toda a troca de dados termina e o cliente pode desligar ativamente.
Programação de soquete no cliente e servidor
A família é geralmente AF_INET sob o protocolo IPV4 e AF_INET6 sob o protocolo IPv6. O tipo é SOCK_STREAM no protocolo de transmissão TCP e SOCK_DGRAM no protocolo UDP. De modo geral, o protocolo de parâmetro do soquete de função é definido como 0, a menos que seja usado no soquete original
A função de conexão do cliente estabelece um link com o servidor
O cliente TCP usa a função de conexão para estabelecer uma conexão com o servidor TCP.
sockfd é o valor de retorno da função de soquete. O segundo parâmetro é um ponteiro para a estrutura de endereço de soquete e o terceiro parâmetro é o tamanho da estrutura.
sin_port é o número da porta e S_addr é o endereço IP da rede do servidor. Através deste programa, o cliente pode se conectar à porta e ip do cliente, ou seja, estabelecer um link.
bind bind socket e porta ip
O Bind atribui um endereço de protocolo local ao soquete. Para protocolos de rede, o endereço de protocolo é um endereço IPv4 de 32 bits ou um endereço IPv6 de 128 bits.
O primeiro parâmetro é o valor de retorno da função de soquete, e o segundo e o terceiro são os mesmos descritos na função de conexão.
Estabeleça dois objetos de soquete, um para o servidor e outro para o cliente.
Servidor escuta fila de escuta
listen só é chamado pelo servidor TCP e
executa principalmente duas funções: backlog se refere ao número máximo de links. Para um determinado soquete de escuta, o kernel mantém duas filas:
1. Para completar a fila de link
2.
Antes do backlog da fila de conexão incompleta, ele foi definido como o valor máximo da soma das duas filas. Normalmente, no ambiente de teste, defina o backlog como 5. Mas está longe de ser suficiente para servidores modernos. Lembre-se de que o backlog não pode ser definido como 0, o que causará defeitos no programa. Se você não quiser que outras pessoas se conectem, feche esta porta.
Aceitar do lado do servidor
Aceitar é chamado pelo servidor para vincular a solicitação de conexão enviada pelo cliente, estabelecendo assim uma conexão por meio de três ondas de mãos.
Observe que se a execução da aceitação for bem-sucedida, o valor de retorno é um novo descritor gerado automaticamente pelo kernel, representando a conexão TCP com o cliente. Esse descritor é chamado de soquete conectado e o valor de retorno da função de soquete é chamado de soquete de escuta. Um soquete de escuta sockfd geralmente gera apenas um no programa do servidor e sempre existe. O soquete C conectado significa que o cliente e o servidor concluíram o handshake triplo.Quando o cliente se desconecta, o soquete C é fechado.
Obviamente, se C <0, significa que o estabelecimento do link falhou, e ele irá bloquear e esperar que o cliente se conecte.
escrever 和 ler
A gravação e a leitura são dois estados, representando o processamento de dados e o recebimento de dados, respectivamente. Por exemplo, quando o programa se comunica, geralmente a escrita é representada pela chamada do sistema de envio e a leitura é geralmente representada pela chamada do sistema recv.
Enviar e receber no lado do cliente: Enviar e receber no lado do
servidor:
Feche o soquete
Neste ponto, o processo de programação do soquete TCP basicamente acabou, e você só precisa fechar o descritor do soquete.
Resultado experimental
Aperto de mão de três vias para estabelecer um link:
continuar a ler dados e enviar dados do cliente:
código-fonte do servidor:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(-1!=sockfd);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr)); //注意memset是取地址
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//主机转网络字节,网络是大段;
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5); //以完成3次握手队列长度是5
while(1)
{
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
//这里是c也是套接字,类似与上面代码的sockfd;
if(c<0)
{
continue;
}
printf("accept c=%d\n",c); //链接套接子
while(1)
{
char buff[128]={
0};
int n=recv(c,buff,127,0);
//如果对方关闭了发送,recv返回0;-1是失败
if(n<=0)
{
break;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
close(c);
}
}
Código-fonte do cliente:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res =connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
while(1)
{
char buff[128]={
0};
printf("input:\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
memset(buff,0,128);
recv(sockfd,buff,128,0);
printf("buff=%s\n",buff);
}
exit(0);
}