Linux环境下实现实现简单 TCP通信demo。
例程一:client端和serve端相互发送接收,打印接收到的内容即退出结束。这里使用的IP地址是本机环回地址“127.0.0.1”,只能进行本地通信。
1 localhost、127.0.0.1和0.0.0.0和本机IP的区别 2 localhost 3 localhost其实是域名,一般windows系统默认将localhost指向127.0.0.1,但是localhost并不等于127.0.0.1,localhost指向的IP地址是可以配置的 4 5 127.0.0.1 6 首先我们要先知道一个概念,凡是以127开头的IP地址,都是回环地址(Loop back address),其所在的回环接口一般被理解为虚拟网卡,并不是真正的路由器接口。 7 8 所谓的回环地址,通俗的讲,就是我们在主机上发送给127开头的IP地址的数据包会被发送的主机自己接收,根本传不出去,外部设备也无法通过回环地址访问到本机。 9 10 小说明:正常的数据包会从IP层进入链路层,然后发送到网络上;而给回环地址发送数据包,数据包会直接被发送主机的IP层获取,后面就没有链路层他们啥事了。 11 12 而127.0.0.1作为{127}集合中的一员,当然也是个回环地址。只不过127.0.0.1经常被默认配置为localhost的IP地址。 13 一般会通过ping 127.0.0.1来测试某台机器上的网络设备是否工作正常。 14 15 0.0.0.0 16 首先,0.0.0.0是不能被ping通的。在服务器中,0.0.0.0并不是一个真实的的IP地址,它表示本机中所有的IPV4地址。监听0.0.0.0的端口,就是监听本机中所有IP的端口。 17 18 本机IP 19 本机IP通常仅指在同一个局域网内,能同时被外部设备访问和本机访问的那些IP地址(可能不止一个)。像127.0.0.1这种一般是不被当作本机IP的。本机IP是与具体的网络接口绑定的,比如以太网卡、无线网卡或者PPP/PPPoE拨号网络的虚拟网卡,想要正常工作都要绑定一个地址,否则其他设备就不知道如何访问它 20 21 22 链接:https://www.jianshu.com/p/ad7cd1d5be45
代码如下:
client code:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> int main(){ //创建套接字 int sock = socket(AF_INET, SOCK_STREAM, 0); //向服务器(特定的IP和端口)发起请求 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充 serv_addr.sin_family = AF_INET; //使用IPv4地址 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址 serv_addr.sin_port = htons(1234); //端口 while (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) { sleep(1); printf("wait serve\r\n"); } //读取服务器传回的数据 char buffer[40]; read(sock, buffer, sizeof(buffer)-1); printf("Message form server: %s\n", buffer); //向serve端发送数据 char str[] = "Hello!"; int count = 0, err; while ((err = write(sock, str, sizeof(str))) <= 0 && count++ < 10) { printf("wait %d\n", err); sleep(1); } //关闭套接字 close(sock); return 0; }
serve code:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main(){ //创建套接字 int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //将套接字和IP、端口绑定 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充 serv_addr.sin_family = AF_INET; //使用IPv4地址 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址 serv_addr.sin_port = htons(1234); //端口 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //进入监听状态,等待用户发起请求 listen(serv_sock, 20); printf("监听结束\n"); //接收客户端请求 struct sockaddr_in clnt_addr; socklen_t clnt_addr_size = sizeof(clnt_addr); int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); //向客户端发送数据 char str[] = "Hello World!"; write(clnt_sock, str, sizeof(str)); //读取client传回的数据 char buffer[40]; int err, count = 0; while ( (err = read(clnt_sock, buffer, sizeof(buffer)-1)) <= 0 && count++ < 10) { printf("wait %d\n", err); sleep(1); } printf("Message form client: %s\n", buffer); //关闭套接字 close(clnt_sock); close(serv_sock); return 0; }
运行演示效果:
例程二:client和serve都创建一个线程进行获取输入和发送输入内容,原来主线程会将接收到的内容打印出来,当输入内容或则接收内容为“bye”时将退出程序运行。这里serve是运行在IP地址为"172.16.194.184"的虚拟机上,所以client和serve的对应代码需要修改serve的IP地址。I
IP地址的查看方法:输入ifconfig指令:
代码如下:
client code:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <arpa/inet.h> 6 #include <sys/socket.h> 7 #include <pthread.h> 8 9 10 int getchar_input_str(char * input_buff); 11 12 int g_flag_exit = 0; 13 char input_str[100], read_buff[100]; 14 int clnt_sock_fd; 15 16 17 18 void * TCP_send(void *arg) 19 { 20 int input_count = 0; 21 22 while(1) { 23 printf("self:"); 24 input_count = getchar_input_str(input_str); 25 send(clnt_sock_fd, input_str, input_count + 1, 0); 26 27 //printf("client:[%d] %s\n", input_count, input_str); 28 if (input_str[0] == ‘b‘ && input_str[1] == ‘y‘ && input_str[2] == ‘e‘) { 29 g_flag_exit = 1; 30 31 return NULL; 32 } 33 } 34 35 } 36 37 38 39 int main() 40 { 41 42 //创建套接字 43 clnt_sock_fd = socket(AF_INET, SOCK_STREAM, 0); 44 45 //向服务器(特定的IP和端口)发起请求 46 struct sockaddr_in serv_addr; 47 memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充 48 serv_addr.sin_family = AF_INET; //使用IPv4地址 49 serv_addr.sin_addr.s_addr = inet_addr("172.16.194.184"); //具体的IP地址 50 serv_addr.sin_port = htons(1234); //端口 51 52 53 54 while (connect(clnt_sock_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) { 55 sleep(1); 56 printf("wait serve connect\r\n"); 57 } 58 59 pthread_t tid; 60 pthread_create(&tid, NULL, TCP_send, "TCP_send"); 61 62 while(1) { 63 64 recv(clnt_sock_fd, read_buff, sizeof(read_buff)-1, 0); 65 printf("\033[5D"); 66 printf("Message form serve: %s\r\nself:", read_buff); 67 fflush(stdout); 68 if (read_buff[0] == ‘b‘ && read_buff[1] == ‘y‘ && read_buff[2] == ‘e‘) { 69 printf("exit connect\r\n"); 70 //send(clnt_sock_fd, "bye!", 5, 0); 71 pthread_cancel(tid); 72 73 break; 74 } 75 76 if (g_flag_exit) 77 break; 78 } 79 80 printf("\n"); 81 82 //关闭套接字 83 close(clnt_sock_fd); 84 85 return 0; 86 } 87 88 89 90 91 /* 92 *@brief 通过getchar()获取输入的字符串 93 *@param buff:存放输入字符串 94 *@return count:输入的字符数 95 * */ 96 int getchar_input_str(char * input_buff) 97 { 98 char input_char, count = 0; 99 100 /*获取输入字符*/ 101 while((input_char = getchar()) != ‘\n‘){ 102 input_buff[count] = input_char; 103 count ++; 104 } 105 /*清除键盘输入缓存*/ 106 if(input_char != ‘\n‘){ 107 while(((input_char = getchar()) != ‘\n‘) && (input_char != EOF)); 108 } 109 /*字符串结尾以‘\0’结束*/ 110 input_buff[count] = ‘\0‘; 111 112 return count; 113 114 }
serve code:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <arpa/inet.h> 6 #include <sys/socket.h> 7 #include <pthread.h> 8 9 10 int getchar_input_str(char * input_buff); 11 12 int g_flag_exit = 0; 13 char input_str[100], read_buff[100]; 14 int serv_sock_fd; 15 int clnt_sock_fd; 16 17 18 19 void * TCP_send(void *arg) 20 { 21 int input_count = 0; 22 23 while(1) { 24 printf("self:"); 25 input_count = getchar_input_str(input_str); 26 send(clnt_sock_fd, input_str, input_count + 1, 0); 27 28 //printf("serve:[%d] %s\n", input_count, input_str); 29 if (input_str[0] == ‘b‘ && input_str[1] == ‘y‘ && input_str[2] == ‘e‘) { 30 g_flag_exit = 1; 31 32 return NULL; 33 } 34 } 35 36 } 37 38 39 40 int main() 41 { 42 43 //创建套接字 44 serv_sock_fd = socket(AF_INET, SOCK_STREAM, 0); 45 46 //向服务器(特定的IP和端口)发起请求 47 struct sockaddr_in serv_addr; 48 memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充 49 serv_addr.sin_family = AF_INET; //使用IPv4地址 50 serv_addr.sin_addr.s_addr = inet_addr("172.16.194.184"); //具体的IP地址 51 serv_addr.sin_port = htons(1234); //端口 52 53 bind(serv_sock_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 54 55 //进入监听状态,等待用户发起请求 56 listen(serv_sock_fd, 20); 57 printf("监听结束\n"); 58 //接收客户端请求 59 struct sockaddr_in clnt_addr; 60 socklen_t clnt_addr_size = sizeof(clnt_addr); 61 clnt_sock_fd = accept(serv_sock_fd, (struct sockaddr*)&clnt_addr, &clnt_addr_size); 62 63 printf("accept end\r\n"); 64 65 pthread_t tid; 66 pthread_create(&tid, NULL, TCP_send, "TCP_send"); 67 68 while(1) { 69 recv(clnt_sock_fd, read_buff, sizeof(read_buff)-1, 0); 70 printf("\033[5D"); 71 printf("Message form client: %s\r\nself:", read_buff); 72 fflush(stdout); 73 if (read_buff[0] == ‘b‘ && read_buff[1] == ‘y‘ && read_buff[2] == ‘e‘) { 74 printf("exit connect\r\n"); 75 //send(clnt_sock_fd, "bye!", 5, 0); 76 pthread_cancel(tid); 77 78 break; 79 } 80 81 if (g_flag_exit) 82 break; 83 } 84 85 printf("\n"); 86 87 //关闭套接字 88 close(clnt_sock_fd); 89 close(serv_sock_fd); 90 91 return 0; 92 } 93 94 95 96 97 /* 98 *@brief 通过getchar()获取输入的字符串 99 *@param buff:存放输入字符串 100 *@return count:输入的字符数 101 * */ 102 int getchar_input_str(char * input_buff) 103 { 104 char input_char, count = 0; 105 106 /*获取输入字符*/ 107 while((input_char = getchar()) != ‘\n‘){ 108 input_buff[count] = input_char; 109 count ++; 110 } 111 /*清除键盘输入缓存*/ 112 if(input_char != ‘\n‘){ 113 while(((input_char = getchar()) != ‘\n‘) && (input_char != EOF)); 114 } 115 /*字符串结尾以‘\0’结束*/ 116 input_buff[count] = ‘\0‘; 117 118 return count; 119 120 }
演示效果: