实现使用TCP网络协议进行数据的服务端和客户端数据相互发送和接收
目录
实现使用TCP网络协议进行数据的服务端和客户端数据相互发送和接收
服务端程序
/*******************************************************************
* file name: TCP_server.c
* author : 17666589210@163.com
* date : 2024-06-06
* fileinfo : 通过使用TCP网络协议实现将终端输入的数据发送数据给客户端,也
* 可以接收来自客户端的数据并打印在终端上
* note : None
* version : 1.0
* CopyRight (c) 2024 17666589210@163.com Right Reseverd
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#define PORT 7778 // 端口号
#define BUFFER_SIZE 1024 // 数组元素个数
struct sockaddr_in server_addr; // 套接字ip信息结构体用于绑定信息
int connect_fd; // accept返回值,文件标识符
// 发送数据的线程
/********************************************************************
*
* name : send_thread
* function : 用于发送TCP协议数据的线程
* argument : none
* retval : 调用成功返回生成文件后的结果
* author : 17666589210@163.com
* date : 2024/06/06
* note : none
*
* *****************************************************************/
void *send_thread(void *arg)
{
char input[BUFFER_SIZE]; // 需要发送数据的缓存区
while (1)
{
// 获取用户输入的数据
printf("Please enter message to send: ");
fgets(input, BUFFER_SIZE, stdin);
// 将获取的数据发送给客户端
send(connect_fd, input, sizeof(input), 0);
printf("Message send success !!!\n");
}
}
// 接收数据的线程
/********************************************************************
*
* name : receive_thread
* function : 用于接收TCP协议数据的线程
* argument : none
* retval : 调用成功返回生成文件后的结果
* author : 17666589210@163.com
* date : 2024/06/06
* note : none
*
* *****************************************************************/
void *receive_thread(void *arg)
{
int valread;
char buffer[BUFFER_SIZE] = {0}; // 需要接收数据的缓存区
while (1)
{
// 接收来自客户端的数据
valread = read(connect_fd, buffer, BUFFER_SIZE);
if (valread == -1)
{
continue;
}
printf("recv from [%s],data is = %s\n", inet_ntoa(server_addr.sin_addr), buffer);
bzero(buffer, sizeof(buffer));
}
}
int main(int argc, char const *argv[])
{
// 1.创建TCP协议套接字
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_socket == -1)
{
fprintf(stderr, "tcp socket error,errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 2.绑定自身的IP地址和端口
int server_addrlen = sizeof(server_addr);
server_addr.sin_family = AF_INET; // 协议族,是固定的
server_addr.sin_port = htons(PORT); // 目标端口,必须转换为网络字节序
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 目标地址 INADDR_ANY 这个宏是一个整数,所以需要使用htonl转换为网络字节序
if (bind(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
fprintf(stderr, "bind socket error, errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 3.设置监听 队列最大容量是5
if (listen(tcp_socket, 5) < 0)
{
fprintf(stderr, "listen error, errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 4.等待接受客户端的连接请求
connect_fd = accept(tcp_socket, (struct sockaddr *)&server_addr, (socklen_t *)&server_addrlen); // 会阻塞
if (connect_fd == -1)
{
fprintf(stderr, "connect error, errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 5.创建两个线程分别来进行接收数据和发送数据的线程
pthread_t send_tid, receive_tid;
pthread_create(&send_tid, NULL, send_thread, NULL);
pthread_create(&receive_tid, NULL, receive_thread, NULL);
// 等待线程计结束进行资源回收
pthread_join(send_tid, NULL);
pthread_join(receive_tid, NULL);
return 0;
}
客户端程序
/*******************************************************************
* file name: TCP_client.c
* author : 17666589210@163.com
* date : 2024-06-06
* fileinfo : 通过使用TCP网络协议实现将终端输入的数据发送数据给服务器,也
* 可以接收来自服务器的数据并打印在终端上
* note : None
* version : 1.0
* CopyRight (c) 2024 17666589210@163.com Right Reseverd
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#define CLIENT_IP "192.168.64.191" // 客户端的ip地址
#define PORT 7778 // 端口号
#define BUFFER_SIZE 1024 // 数组元素个数
int tcp_socket;
int connect_fd;
struct sockaddr_in server_addr;
// 发送数据的线程
/********************************************************************
*
* name : send_thread
* function : 用于发送TCP协议数据的线程
* argument : none
* retval : 调用成功返回生成文件后的结果
* author : 17666589210@163.com
* date : 2024/06/06
* note : none
*
* *****************************************************************/
void *send_thread(void *arg)
{
char input[BUFFER_SIZE];
while (1)
{
// 获取用户输入的数据
printf("Please enter message to send: ");
fgets(input, BUFFER_SIZE, stdin);
// 将获取的数据发送给客户端
send(tcp_socket, input, sizeof(input), 0);
printf("Message send success !!!\n");
}
}
// 接收数据的线程
/********************************************************************
*
* name : receive_thread
* function : 用于接收TCP协议数据的线程
* argument : none
* retval : 调用成功返回生成文件后的结果
* author : 17666589210@163.com
* date : 2024/06/06
* note : none
*
* *****************************************************************/
void *receive_thread(void *arg)
{
int valread;
char buffer[BUFFER_SIZE] = {0};
while (1)
{
// 接收来自客户端的数据
valread = read(tcp_socket, buffer, BUFFER_SIZE);
if (valread == -1)
{
continue;
}
printf("recv from [%s],data is = %s\n", inet_ntoa(server_addr.sin_addr), buffer);
bzero(buffer, sizeof(buffer));
}
}
int main()
{
// 1.创建TCP协议套接字
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_socket == -1)
{
fprintf(stderr, "tcp socket error,errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
server_addr.sin_family = AF_INET; // 协议族,是固定的
server_addr.sin_port = htons(PORT); // 目标端口,必须转换为网络字节序
// 2.绑定自身的IP地址和端口
if (inet_pton(AF_INET, CLIENT_IP, &server_addr.sin_addr) <= 0)
{
fprintf(stderr, "inet error,errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 3.发出连接请求到服务器
connect_fd = connect(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (connect_fd < 0)
{
fprintf(stderr, "connect error,errno:%d,%s\n", errno, strerror(errno));
exit(1);
}
// 4.创建两个线程分别来进行接收数据和发送数据的线程
pthread_t send_tid, receive_tid;
pthread_create(&send_tid, NULL, send_thread, NULL);
pthread_create(&receive_tid, NULL, receive_thread, NULL);
// 等待线程计结束进行资源回收
pthread_join(send_tid, NULL);
pthread_join(receive_tid, NULL);
return 0;
}