当前位置: 代码迷 >> 综合 >> 【linux网络编程学习笔记】第二节:创建TCP通信(双向)(socket、bind、listen、accept、connect、recv、send、shutdown、server\client)
  详细解决方案

【linux网络编程学习笔记】第二节:创建TCP通信(双向)(socket、bind、listen、accept、connect、recv、send、shutdown、server\client)

热度:63   发布时间:2024-02-08 00:35:38.0

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;
}

 

  相关解决方案