1 TCP实现客户端和服务器的读和写
服务器端
cpp#include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;} void *read_from_server(void *arg) { //使用recv接收客户端发送数据,打印到控制台 char *read_buf = NULL; int client_fd = *(int *)arg; read_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!read_buf) { perror("malloc server read_buf"); return NULL; } //接收数据 while(count = recv(client_fd,read_buf,1024,0)) { if(count < 0) { perror("recv"); return NULL; } fputs(read_buf,stdout); } printf("服务端请求关闭\n"); free(read_buf); return NULL; } void *write_to_server(void *arg) { //接收控制台输入的信息,写进去 char *write_buf = NULL; int client_fd = *(int *)arg; write_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!write_buf) { perror("malloc server write_buf"); return NULL; } while(fgets(write_buf,1024,stdin) != NULL) { count = send(client_fd,write_buf,1024,0); if(count < 0) { perror("send"); return NULL; } } printf("接收到控制台的关闭请求,不再写入,关闭连接\n"); shutdown(client_fd,SHUT_WR); free(write_buf); return NULL; } int main() { struct sockaddr_in server_addr,client_addr; pthread_t pid_read,pid_write; memset(&server_addr,0,sizeof(server_addr)); memset(&client_addr,0,sizeof(client_addr)); //网络编程流程 //1、创建socket int sockfd = socket(AF_INET,SOCK_STREAM,0); handle_error("socket",sockfd); //2、主动连接服务端 server_addr.sin_family = AF_INET; inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr); server_addr.sin_port = htons(8888); int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); handle_error("connect",temp_result); printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port)); //创建子线程用于收消息 pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd); //创建子线程用于发消息 pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); //阻塞主线程 pthread_join(pid_read,NULL); pthread_join(pid_write,NULL); printf("释放资源"); close(sockfd); return 0; }客户端
cpp#include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;} void *read_from_server(void *arg) { //使用recv接收客户端发送数据,打印到控制台 char *read_buf = NULL; int client_fd = *(int *)arg; read_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!read_buf) { perror("malloc server read_buf"); return NULL; } //接收数据 while(count = recv(client_fd,read_buf,1024,0)) { if(count < 0) { perror("recv"); return NULL; } fputs(read_buf,stdout); } printf("服务端请求关闭\n"); free(read_buf); return NULL; } void *write_to_server(void *arg) { //接收控制台输入的信息,写进去 char *write_buf = NULL; int client_fd = *(int *)arg; write_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!write_buf) { perror("malloc server write_buf"); return NULL; } while(fgets(write_buf,1024,stdin) != NULL) { count = send(client_fd,write_buf,1024,0); if(count < 0) { perror("send"); return NULL; } } printf("接收到控制台的关闭请求,不再写入,关闭连接\n"); shutdown(client_fd,SHUT_WR); free(write_buf); return NULL; } int main() { struct sockaddr_in server_addr,client_addr; pthread_t pid_read,pid_write; memset(&server_addr,0,sizeof(server_addr)); memset(&client_addr,0,sizeof(client_addr)); //网络编程流程 //1、创建socket int sockfd = socket(AF_INET,SOCK_STREAM,0); handle_error("socket",sockfd); //2、主动连接服务端 server_addr.sin_family = AF_INET; inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr); server_addr.sin_port = htons(8888); int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); handle_error("connect",temp_result); printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port)); //创建子线程用于收消息 pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd); //创建子线程用于发消息 pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); //阻塞主线程 pthread_join(pid_read,NULL); pthread_join(pid_write,NULL); printf("释放资源"); close(sockfd); return 0; }
sudo netstat -tanlp
这个指令可以监控TCP运行情况
sudo apt install wireshark
这个指令用来安装可视化查看网络连接app,下载好之后不要直接打开,通过指令打开:
sudo wireshark
2 TCP实现多连接客户端与服务器端
服务器端
cpp#include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;} void*read_from_client_write(void *arg) { //读取客户端发送过来的数据 回复收到 int client_fd = *(int *)arg; char *read_buf = NULL; char *write_buf = NULL; ssize_t count = 0,send_count = 0; read_buf = malloc(sizeof(char)*1024); write_buf = malloc(sizeof(char)*1024); if(!read_buf) { printf("初始化读缓冲失败\n"); close(client_fd); perror("read_buf"); return NULL; } if(!write_buf) { printf("初始化写缓冲失败\n"); close(client_fd); perror("write_buf"); return NULL; } while(count = recv(client_fd,read_buf,1024,0)) { if(count < 0) { perror("recv"); return NULL; } //接收数据打印到控制台 printf("从%d客户端收到数据%s\n",client_fd,read_buf); //把收到的数据写入到写缓冲器中 strcpy(write_buf,"收到\n"); send_count = send(client_fd,write_buf,1024,0); if(send_count < 0) { perror("send"); return NULL; } } //当客户端输入ctrl+d结束循环 close(client_fd); free(read_buf); free(write_buf); } int main() { struct sockaddr_in server_addr,client_addr; memset(&server_addr,0,sizeof(server_addr)); memset(&client_addr,0,sizeof(client_addr)); //填写服务端地址 server_addr.sin_family = AF_INET; //填写ip地址0.0.0.0 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //第二种ip地址写法:inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr); //填写端口号 server_addr.sin_port = htons(8888); //网络编程流程 //1、socket int sockfd = socket(AF_INET,SOCK_STREAM,0); handle_error("socket",sockfd); //2、绑定地址 int temp_result = bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); handle_error("bind",temp_result); //3、进入监听状态 temp_result = listen(sockfd,80); handle_error("bind",temp_result); //4、获取客户端的连接,返回的文件描述符才是能够和客户端收发消息的 //需要能够接收多个连接 socklen_t cliaddr_len = sizeof(client_addr); while(1) { pthread_t pid_read_write; int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&cliaddr_len); handle_error("accept",clientfd); printf("与客户端%s %d 建立连接\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); //和每一个客户端使用一个线程交互 把客户端发送的信息打印到控制台 回复收到 if(pthread_create(&pid_read_write,NULL,read_from_client_write,(void*)&clientfd)) { perror("pthread_create"); return 1; } //需要等待线程结束,但是不能挂起 pthread_detach(pid_read_write); } printf("释放资源\n"); close(sockfd); return 0; }客户端
cpp#include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;} void *read_from_server(void *arg) { //使用recv接收服务端发送数据,打印到控制台 char *read_buf = NULL; int client_fd = *(int *)arg; read_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!read_buf) { perror("malloc server read_buf"); return NULL; } //接收数据 while(count = recv(client_fd,read_buf,1024,0)) { if(count < 0) { perror("recv"); return NULL; } fputs(read_buf,stdout); } printf("服务端请求关闭\n"); free(read_buf); return NULL; } void *write_to_server(void *arg) { //接收控制台输入的信息,写进去 char *write_buf = NULL; int client_fd = *(int *)arg; write_buf = malloc(sizeof(char)*1024); ssize_t count = 0; if(!write_buf) { perror("malloc server write_buf"); return NULL; } while(fgets(write_buf,1024,stdin) != NULL) { count = send(client_fd,write_buf,1024,0); if(count < 0) { perror("send"); return NULL; } } printf("接收到控制台的关闭请求,不再写入,关闭连接\n"); shutdown(client_fd,SHUT_WR); free(write_buf); return NULL; } int main() { struct sockaddr_in server_addr,client_addr; pthread_t pid_read,pid_write; memset(&server_addr,0,sizeof(server_addr)); memset(&client_addr,0,sizeof(client_addr)); //网络编程流程 //1、创建socket int sockfd = socket(AF_INET,SOCK_STREAM,0); handle_error("socket",sockfd); //2、主动连接服务端 server_addr.sin_family = AF_INET; inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr); server_addr.sin_port = htons(8888); int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); handle_error("connect",temp_result); printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port)); //创建子线程用于收消息 pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd); //创建子线程用于发消息 pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); //阻塞主线程 pthread_join(pid_read,NULL); pthread_join(pid_write,NULL); printf("释放资源"); close(sockfd); return 0; }