TCP服务器、客户端的简单实现

xiaoxiao2021-02-28  121

1.  IP地址(IPV4   IPV6)    以一个32位的整形表示: 172.166.111.110  -》点分10进程       地址        255.255.255.255     表示为     FF   FF   FF  FF   ->二进程   2.IP地址分类 A类地址:0.0.0.0    --   127.255.255.255                                网络号 +  主机号  网络号高(0-7)  主机号低(8—31) B类地址:128.0.0.0  --   191.255.255.255                        网络号高(0-15) 主机号低(16-31) C类地址: 192.0.0.0  --   223.255.255.255                        网络号高(0-23) 主机号低(24-31) D类地址:224.0.0.0  --   239.255.255.255                        用来做组播网络 E类地址:240.0.0.0  --   255.255.255.255                        用来做广播网络  说明: 网络号  -》识别是那个网络                  主机号  -》识别是那一台PC 192.168.7.6    ---》  C类地址       网络通信时必须要地址段相同 192.168.6.6    ---》  C类地址 3.端口号    -》识别主机中的哪一个进程 IP地址:识别网络中的那一套主机,端口号就是用来识别,当前主机中的哪一个进程 端口号的取值范围:1-65535     在使用端口号时要注意:一般使用1000以后的端口号,因为1000以前的端口号,一般被系统进程占用着 ----------------------------------------------------------------------------------------------------- 传输层协议: TCP协议     UDP协议 TCP协议可靠传输协议:一般用于文件传输,与控制命令传输。 UDP协议不可传输协议:一般用于多媒体体数据传输,例如 音频,视屏 TCP协议的搭建流程: -----------------------------客户端----------------------------------- 1.创建socket   头文件:       #include <sys/types.h>          /* See NOTES */       #include <sys/socket.h> 函数原型:        int socket(int domain, int type, int protocol); 参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)                             AF_INET6            IPv6 Internet protocols          ipv6(7)                                      AF_IPX              IPX - Novell protocols 参数二:传输协议       SOCK_STREAM    ---》TCP协议                       SOCK_DGRAM     ---》UDP协议 参数三:socket的属性    填写为0 默认属性 返回值:成功发回 新的socket文件描述符 , 失败返回  -1 2.链接服务器  connect  (难点!!!!!!!!重点!!!) 头文件:           #include <sys/types.h>          /* See NOTES */         #include <sys/socket.h> 函数原型:           int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 参数一:socket文件描述符 参数二:服务器信息结构体 参数三:服务器信息结构体的大小 返回值:链接成功返回0  链接失败返回-1 const struct sockaddr *addr 服务器信息结构体  他的所在路径为 /usr/include/linux/in.h struct sockaddr  与 struct sockaddr_in 在使用上是等价的。 struct sockaddr_in结构体介绍: struct sockaddr_in {   __kernel_sa_family_t sin_family; /* Address family协议族 IPV4 还是IPV6协议*/   __be16 sin_port; /* Port number端口号*/   struct in_addr sin_addr; /* Internet addressIP地址*/ }  /* Internet address. */IP地址结构体 struct in_addr { __be32 s_addr; }; IP地址转换函数: #include <sys/socket.h> #include <netinet/in.h>  -》会与linux/in.h冲突,所以在加入点分10进制转换函数后要把原来那个头文件去掉 #include <arpa/inet.h> in_addr_t inet_addr(const char *cp);   -》点分10进制转整形  char *inet_ntoa(struct in_addr in);   -》整形转点分10进制类型 大小端格式:在网络通信中都使用大端格式进行通信(所以我们需要转换端口号) 大端格式:低地址存储高位字节 小段格式:低地址存储低位字节     uint16_t htons(uint16_t hostshort); -》主机序转网络序     uint16_t ntohs(uint16_t netshort);  -》网络序转主机序 --------------------------------服务器端---------------------------------------- 1.创建socket   头文件:       #include <sys/types.h>          /* See NOTES */       #include <sys/socket.h> 函数原型:        int socket(int domain, int type, int protocol); 参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)                             AF_INET6            IPv6 Internet protocols          ipv6(7)                                      AF_IPX              IPX - Novell protocols 参数二:传输协议      SOCK_STREAM    ->TCP协议                       SOCK_DGRAM     -》UDP协议 参数三:socket的属性    填写为0 默认属性 返回值:成功发回 新的socket文件描述符 , 失败返回  -1 2.绑定socket 头文件:           #include <sys/types.h>          /* See NOTES */         #include <sys/socket.h> 函数原型:            int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 参数一:创建的socket文件描述符 参数二:服务器绑定信息 参数三:服务器信息结构体的大小 返回值:成功返回0 ,失败返回-1 3.设置为监听socket 头文件:            #include <sys/types.h>          /* See NOTES */         #include <sys/socket.h> 函数原型:              int listen(int sockfd, int backlog);  参数一:创建的socket文件描述符  参数二:最大监听数  (同时可以接受多少个客户端的链接请求)  返回值:成功返回0  失败返回-1. 4.链接服务器  (重点!!!) 他会阻塞等待客户端链接过来 头文件:           #include <sys/types.h>          /* See NOTES */           #include <sys/socket.h> 函数原型:              int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 参数一:监听的文件描述符 参数二:客户端的信息结构体(例如客户端的IP,端口号) 参数三:成功接受客户端的信息结构体大小 返回值:接受链接请求成功,返回一个新的文件描述符,失败返回-1 -------------------------------------------------------------------------------------------------------------------------------------- 练习:tcp服务器和客户端的简单通信实现 【server.c】 #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> //写操作 void *write_fun(void *arg) { int fd=*(int *)arg; char buf[50]={0}; //输入指令 while(1) { scanf("%s",buf); write(fd,buf,strlen(buf)); } } //读操作 void *read_fun(void *arg) { int fd=*(int *)arg; char buf[50]={0}; //输入指令 while(1) { bzero(buf,50); read(fd,buf,50); printf("buf=%s\n",buf); } } int main(int argv,char **argc) { if(argv<3) { perror("plese input ./server prot ip"); return 0; } //1.创建TCP socket int sockfd=socket( AF_INET,SOCK_STREAM ,0); if(sockfd<0) { perror("create sock fail\n"); } else { printf("create sock %d\n",sockfd); } //设置服务器绑定信息 struct sockaddr_in serveraddr; bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET ; //IPV4协议 serveraddr.sin_port = htons(atoi(argc[1])); //端口号 serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址 "0.0.0.0" ->万用地址 // htonl(INADDR_ANY) //INADDR_ANY ->万用IP宏 //2.绑定服务器 int ret=bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); if(ret != 0) { perror("bind fail\n"); } else { printf("bind ok\n"); } //3.设置为监听socket ret=listen(sockfd,5); if(ret != 0) { perror("listen fail\n"); } else { printf("listen ok\n"); } //定义一个结构体保存客户端的信息 struct sockaddr_in clienaddr; bzero(&clienaddr,sizeof(clienaddr)); //定义一个整形保存接收的长度 socklen_t len=sizeof(clienaddr); //4.接收客户端的链接请求(重点!!!) while(1) { int newfd=accept(sockfd,(struct sockaddr *)&clienaddr,&len); if(newfd>0) { printf("accept OK fd=%d\n",newfd); printf("clien ip=%s,port=%d\n",inet_ntoa(clienaddr.sin_addr),ntohs(clienaddr.sin_port)); //写入信息携程 pthread_t pid; pthread_create(&pid,NULL,write_fun,(void *)&newfd); //读取信息线程 pthread_t pid1; pthread_create(&pid1,NULL,read_fun,(void *)&newfd); } else { perror("accept fail\n"); } } } ---------------------------------------------------------------------------------------------------------------------------------------------- 【client.c】 #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> void *write_fun(void *arg) { int fd=*(int *)arg; char buf[50]={0}; //输入指令 while(1) { scanf("%s",buf); write(fd,buf,strlen(buf)); } } int main(int argv,char **argc) { if(argv<3) { perror("plese input ./clien prot ip"); return 0; } //创建TCP socket int sockfd=socket( AF_INET,SOCK_STREAM ,0); if(sockfd<0) { perror("create sock fail\n"); } else { printf("create sock %d\n",sockfd); } //设置服务器信息 struct sockaddr_in serveraddr; bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET ; //IPV4协议 serveraddr.sin_port = htons(atoi(argc[1])); //端口号 serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址 //进行读写操作 char buf[50]={0}; //链接服务器 int ret=connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); if(ret != 0) { perror("connect fail\n"); } else { //使用一个写入线程 pthread_t pid; pthread_create(&pid,NULL,write_fun,(void *)&sockfd); while(1) { bzero(buf,sizeof(buf)); ret=read(sockfd,buf,sizeof(buf)); if(ret>0) { printf("buf=%s\n",buf); } else { perror("read fail\n"); return 0; } } } //写一个简单的聊天客户端 可以进行读写操作 } ----------------------------------------------------------------------------------------------------------- 程序运行时必须 先运行服务器程序,再运行客户端程序,并且设置端口和服务器ip地址          
转载请注明原文地址: https://www.6miu.com/read-66649.html

最新回复(0)