Work won't kill but worry will.
劳动无害,忧愁伤身。
上一篇章中创建了TCP的客户端的服务器,但是只能单向发送,本章节主要讲解如何进行双向互发消息,实现的过程很简单,看过上一阶段的章节就不难发现可以使用线程可,进行一遍发送一遍接收。
废话不多说直接上例程
TCP相关API说明点击跳转
线程相关说明点击跳转
tcp_server.c 服务端
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
void *send_thread(void *arg)
{
int client_fd = *(int *)arg;
char buffer[1024];
ssize_t send_size;
while(1)
{
bzero(buffer, sizeof(buffer));
scanf("%s",buffer);
/*
接受来自与客户端的数据,这个接受具备阻塞特性
跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
*/
send_size = send(client_fd, buffer, strlen(buffer), 0);
if(send_size == -1)
{
perror("发送数据异常");
break;
}
}
return NULL;
}
int main(void)
{
char buffer[1024];
int skt_fd;
int client_fd;
int retval;
ssize_t recv_size;
/*
获取程序通信的套接字(接口)
AF_INET:IPV4的协议
SOCK_STREAM:指定TCP协议
0:代表不变化协议内部(ip手册中指定的参数)
*/
skt_fd = socket( AF_INET, SOCK_STREAM, 0);
if(skt_fd == -1)
{
perror("申请套接字失败");
return -1;
}
//绑定自己的地址信息
struct sockaddr_in native_addr;
//指定引用IPV4的协议
native_addr.sin_family = AF_INET;
//指定端口号,转化为网络字节序(大端序)
native_addr.sin_port = htons(6666);
//将所有的IP地址转化为二进制的网络字节序的数据进行绑定
native_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*
将指定的地址信息及本程序的套接字绑定在一起
skt_fd:套接字的文件描述符
&native_addr:需要绑定的地址信息结构体(每个协议的地址信息结构体是不一样的,
我们用IPV4的协议便需要引用struct sockaddr_in)
sizeof(native_addr):传入的结构体长度
*/
retval = bind( skt_fd, (struct sockaddr *)&native_addr, sizeof(native_addr));
if(retval == -1)
{
perror("绑定套接字地址失败");
close(skt_fd);
return -1;
}
/*
设置套接字的同时通信最大连接数为50,并且将这个套接字的属性设置为可监听属性
*/
retval = listen(skt_fd, 50);
if(retval == -1)
{
perror("设置最大连接数失败");
close(skt_fd);
return -1;
}
//用于接收客户端的地址信息
struct sockaddr_in client_addr;
socklen_t sklen = sizeof(client_addr);
/*
等待客户端链接,链接成功后返回一个代表客户端通信的文件描述符,具备阻塞特性
skt_fd:代表套接字接口
client_addr:链接成功后客户端的地址信息会存放到这里面
sklen:代表结构体的长度
*/
client_fd = accept(skt_fd, (struct sockaddr *)&client_addr, &sklen);
if(client_fd == -1)
{
perror("客户端链接失败");
close(skt_fd);
return -1;
}
printf("服务器:客户端连接成功\n");
printf("客户端信息:\n客户端IP为%s,端口号为%hu\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
//创建发送的子线程
pthread_t tid;
pthread_create(&tid, NULL, send_thread, &client_fd);
while(1)
{
bzero(buffer,sizeof(buffer));
/*
接受来自与客户端的数据,这个接受具备阻塞特性
跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
*/
recv_size = recv(client_fd,buffer,sizeof(buffer),0);
if(recv_size == -1)
{
perror("接受数据异常");
close(skt_fd);
close(client_fd);
return -1;
}else if(recv_size == 0)//代表客户端断开连接
break;
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, buffer);
}
close(client_fd);//关闭客户端通信
close(skt_fd);//关闭服务器的socket资源
return 0;
}
tcp_client.c 客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *recv_data(void *arg)
{
int skt_fd = *(int *)arg;
char buffer[1024];
ssize_t recv_size;
while(1)
{
bzero(buffer, sizeof(buffer));
/*
接受来自与客户端的数据,这个接受具备阻塞特性
跟read函数差不多,都是指定从client_fd里面读取sizeof(buffer)长的数据放到buffer当中,0则代表按照默认操作读取数据
*/
recv_size = recv(skt_fd, buffer, sizeof(buffer), 0);
if(recv_size == -1)
{
perror("接受数据异常");
break;
}
else if(recv_size == 0)//代表服务器断开连接
{
close(skt_fd);
return 0;
}
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, buffer);
}
return NULL;
}
//./client 192.168.33.3
int main(int argc, const char *argv[])
{
char buffer[1024];
int skt_fd;
int retval;
ssize_t send_size;
/*
获取程序通信的套接字(接口)
AF_INET:IPV4的协议
SOCK_STREAM:指定TCP协议
0:代表不变化协议内部(ip手册中指定的参数)
*/
skt_fd = socket( AF_INET, SOCK_STREAM, 0);
if(skt_fd == -1)
{
perror("申请套接字失败");
return -1;
}
//服务器的地址信息
struct sockaddr_in srv_addr;
//指定引用IPV4的协议
srv_addr.sin_family = AF_INET;
//指定端口号,转化为网络字节序(大端序)
srv_addr.sin_port = htons(6666);
//将所有的IP地址转化为二进制的网络字节序的数据进行绑定
srv_addr.sin_addr.s_addr = inet_addr("192.168.32.68");
retval = connect(skt_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if(retval == -1)
{
perror("客户端连接到服务器失败\n");
close(skt_fd);
return -1;
}
printf("客户端:连接服务器成功\n");
//创建接收的子线程
pthread_t tid;
pthread_create(&tid, NULL, recv_data, &skt_fd);
while(1)
{
scanf("%s", buffer);
send_size = send( skt_fd, buffer, strlen(buffer), 0);
if(send_size == -1)
break;
}
close(skt_fd);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)