Programação de rede em linguagem C (2) - comunicação TCP
1. cliente TCP
1. Estabeleça a conexão
Queremos usar o soquete, antes de tudo, primeiro adicionamos o arquivo de cabeçalho a ser usado
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
Crie um soquete tcp, protocolo ipv4, use o parâmetro SOCK_STREAM, o protocolo é 0, ele selecionará automaticamente o protocolo tcp por padrão;
// 1、使用socket()函数获取一个socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
Em seguida, colocamos o endereço IP e o número da porta do servidor em uma estrutura para preparar
// 2、准备服务端的地址和端口,'192.168.0.107'表示目的ip地址,12341表示目的端口号
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET; // 设置地址族为IPv4
server_addr.sin_port = htons(12341); // 设置地址的端口号信息
server_addr.sin_addr.s_addr = inet_addr("192.168.0.107"); // 设置IP地址
Em seguida, use o método connect para conectar, se a conexão for bem-sucedida, ela retornará 0. A falha retornará -1
// 3、链接到服务器
ret = connect(tcp_client, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
perror("connect");
else
printf("connect result, ret = %d.\n", ret);
Por fim, lembre-se de fechar o soquete
// 4、关闭套接字
close(tcp_client);
Compile e execute, a conexão foi bem-sucedida:
2, envie dados
Use a função send () para enviar dados
// 4. 发送数据到服务端
char sendbuf[]={"hello world."};
ret = send(sockfd, sendbuf, strlen(sendbuf),0);
Pode-se observar que os dados foram enviados com sucesso, o servidor recebeu os dados
3.
Se os dados forem recebidos, você poderá usar a função recv para aguardar a recepção.O parâmetro é o número máximo de bytes recebidos e os dados recebidos são impressos. Sair
O código completo é o seguinte:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(void)
{
int ret;
// 1、使用socket()函数获取一个TCP客户端socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_client)
{
perror("socket");
return -1;
}
// 2、准备服务端的地址和端口,'192.168.0.107'表示目的ip地址,12341表示目的端口号
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET; // 设置地址族为IPv4
server_addr.sin_port = htons(12341); // 设置地址的端口号信息
server_addr.sin_addr.s_addr = inet_addr("192.168.0.107"); // 设置IP地址
// 3、链接到服务器
ret = connect(tcp_client, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
perror("connect");
else
printf("connect result, ret = %d.\n", ret);
// 4. 发送数据到服务端
char sendbuf[]={"hello world."};
ret = send(tcp_client, sendbuf, strlen(sendbuf),0);
// 5、等待接收服务端发送过来的数据,最大接收1024个字节
char recvbuf[1024] = {0};
ret = recv(tcp_client, recvbuf, sizeof(recvbuf), 0);
// 6、将接收到的数据打印出来
printf("Recvdate:%s \n",recvbuf);
// 7、关闭套接字
close(tcp_client);
}
Segundo, o servidor TCP
1. Estabeleça o servidor e aguarde a conexão.
Da mesma forma, queremos usar o soquete. Primeiro, adicionamos o arquivo de cabeçalho a ser usado.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
Crie um soquete tcp, protocolo ipv4, use o parâmetro SOCK_STREAM, o protocolo é 0, ele selecionará automaticamente o protocolo tcp por padrão;
// 1、使用socket()函数获取一个socket文件描述符
int tcp_server = socket(AF_INET, SOCK_STREAM, 0);
Para que o cliente se conecte a ele, precisamos vincular um número de porta
// 2. 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号
struct sockaddr_in local_addr = {0};
local_addr.sin_family = AF_INET; // 设置地址族为IPv4
local_addr.sin_port = htons(8266); // 设置地址的端口号信息
local_addr.sin_addr.s_addr = inet_addr("192.168.0.107"); // 设置IP地址
ret = bind(tcp_server, (const struct sockaddr *)&local_addr, sizeof(local_addr));
if (ret < 0)
perror("bind");
else
printf("bind success.\n");
Em seguida, podemos usar o método listen para ouvir conexões.O segundo parâmetro é o número de conexões em fila pelas quais podemos esperar
// 3、listen监听端口,阻塞,等待客户端来连接服务器
ret = listen(sockfd, 5);
Use o método accept para aguardar a conexão do cliente com este servidor, o valor de retorno é o descritor do arquivo de soquete do cliente conectado
// 4、accept阻塞等待客户端接入
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_fd = accept(tcp_server, (struct sockaddr *)&client_addr, &addrlen);
Imprimimos as informações do cliente vinculadas a ele
// 5、打印连接过来的客户端信息及其ip地址
printf("Client from %s:%d \n",inet_ntoa(*(struct in_addr*)&client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
Então podemos fechar o soquete
// 6、关闭套接字
close(tcp_client);
Execute o programa e conecte-se usando o assistente de depuração de rede.Você pode ver que a conexão foi bem-sucedida
2. Receber dados
Quando um cliente se conecta, podemos usar o descritor de arquivo de soquete do cliente para aguardar os dados enviados pela outra parte.
// 5、等待接收对方发送过来的数据
char recvbuf[1024] = {0};
ret = recv(client_fd, recvbuf, sizeof(recvbuf), 0);
printf("Recv from %s:%d, ",inet_ntoa(*(struct in_addr*)&client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
printf("recv_data: %s \n",recvbuf);
Compile, execute e use o cliente assistente de depuração de rede para enviar dados.Os resultados são os seguintes:
3. Enviar dados Depois de
receber os dados, enviamos os dados de volta para informar ao cliente que os recebi.
// 6、返回数据到客户端
char send_buf[1024] = "I have got the date:";
strcat(send_buf,recvbuf);
send(client_fd, send_buf, strlen(send_buf), 0);
Compile e execute o resultado
Código completo
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(void)
{
int ret = -1;
// 1、使用socket()函数获取一个socket文件描述符
int tcp_server = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_server)
{
perror("socket");
return -1;
}
// 2. 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号
struct sockaddr_in local_addr = {0};
local_addr.sin_family = AF_INET; // 设置地址族为IPv4
local_addr.sin_port = htons(8266); // 设置地址的端口号信息
local_addr.sin_addr.s_addr = inet_addr("192.168.0.107"); // 设置IP地址
ret = bind(tcp_server, (const struct sockaddr *)&local_addr, sizeof(local_addr));
if (ret < 0)
perror("bind");
else
printf("bind success.\n");
// 3、listen监听端口,阻塞,等待客户端来连接服务器
ret = listen(tcp_server, 5);
// 4、accept阻塞等待客户端接入
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_fd = accept(tcp_server, (struct sockaddr *)&client_addr, &addrlen);
// 5、等待接收对方发送过来的数据
char recvbuf[1024] = {0};
ret = recv(client_fd, recvbuf, sizeof(recvbuf), 0);
printf("Recv from %s:%d, ",inet_ntoa(*(struct in_addr*)&client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
printf("recv_data: %s \n",recvbuf);
// 6、返回数据到客户端
char send_buf[1024] = "I have got the date:";
strcat(send_buf,recvbuf);
send(client_fd, send_buf, strlen(send_buf), 0);
// 7、关闭套接字
close(tcp_server);
}