C语言网络编程(2)— TCP通信
一、TCP客户端
1、建立连接
我们要使用到socket,首先首先我们添加要使用的头文件
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
创建一个tcp套接字,ipv4协议,使用SOCK_STREAM参数,protocol为0,就会默认自动选择tcp协议;
// 1、使用socket()函数获取一个socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
然后我们把把服务端的ip地址和端口号放在一个结构体里准备好
// 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地址
然后使用connect方法进行连接即可,连接成功则返回0.失败返回-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);
最后记得关闭套接字即可
// 4、关闭套接字
close(tcp_client);
编译运行,连接成功:
2、发送数据
使用send()函数发送数据
// 4. 发送数据到服务端
char sendbuf[]={"hello world."};
ret = send(sockfd, sendbuf, strlen(sendbuf),0);
可以看到,数据发送成功,服务器端已经接收到数据
3、接收数据
如果要接收数据,那么就可以使用recv函数等待接收即可,其参数为最大接收字节数,然后将接收到的数据 打印出来
完整代码如下:
#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);
}
二、TCP服务端
1、建立服务端,等待连接
同样的,我们要使用到socket,首先首先我们添加要使用的头文件
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
创建一个tcp套接字,ipv4协议,使用SOCK_STREAM参数,protocol为0,就会默认自动选择tcp协议;
// 1、使用socket()函数获取一个socket文件描述符
int tcp_server = socket(AF_INET, SOCK_STREAM, 0);
为了让客户端可以连接到,我们需要绑定一个端口号
// 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");
然后我们就可以使用listen方法来监听连接了,第二个参数为可以等待的排队连接数量
// 3、listen监听端口,阻塞,等待客户端来连接服务器
ret = listen(sockfd, 5);
使用accept方法来等待客户端连接到这个服务器,其返回值为连接过来的客户端套接字文件描述符
// 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、打印连接过来的客户端信息及其ip地址
printf("Client from %s:%d \n",inet_ntoa(*(struct in_addr*)&client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
然后我们就可以关闭套接字了
// 6、关闭套接字
close(tcp_client);
运行程序,使用网络调试助手进行连接,可以看到,连接成功
2、接收数据
当有客户端连接进来时,我们就可以使用客户端套接字文件描述符等待接收对方发送过来的数据了
// 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);
编译,运行,使用网络调试助手客户端发送数据,结果如下
3、发送数据
接收到数据以后我们发送数据回去,告诉客户端我已经接受到数据了
// 6、返回数据到客户端
char send_buf[1024] = "I have got the date:";
strcat(send_buf,recvbuf);
send(client_fd, send_buf, strlen(send_buf), 0);
编译,运行结果
完整代码
#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);
}