今天我们用之前讲解过的UDP协议来写一个最基础,最简单的网络聊天程序。
//我们通过udp协议来实现一个简单的网络聊天程序//这是客户端的实现//过程:// 1.创建套接字// 2.绑定地址信息// 3.向服务端发送数据// 4.接受服务端发送的数据// 5.关闭socket#includestdio.h#includestdlib.h#includeunistd.h#includestring.h#includeerrno.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.hint main(){ int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); //socket函数第一个参数为地址类型,目前只支持apra类型的地址 //第二个参数是套接字类型 如果是SOCK_DGRAM 面向数据报的套接字 //如果是SOCK_STREAM则是面向数据流的套接字 不 //第三个参数是用来指定具体协议,不想指定可以省略为0 默认数据报套接字为udp 数据流为tcp //这里我们指定了IP协议族中的UDP协议。 if(sockfd0) { perror("socket error"); return -1; } //绑定地址信息,不过在客户端的时候我们通常不绑定 //因为绑定的话可能会因为一些特殊情况失败,但是 //客户端发送数据的时候使用哪个地址和端口都无所谓 //只要数据能够发送成功就可以,所以客户端时我们一般 //不推荐绑定端口,这样在发送数据的时候,操作系统检测 //到socket还没有绑定地址,就会自动给他绑定一个这样 //绑定方式不会出错。 // struct sockaddr_in cli_addr; //sockaddr_in 是一个结构体解决了sockaddr的缺陷 //里边有四个成员变量分别是: //sin_family 存储地址族 //sin_port 16位TCP/UDP端口号 //sin_addr 32位IP地址 //sin_zeor[8] 我们不会使用到 cli_addr.sin_family=AF_INET; cli_addr.sin_port=htons(9000); cli_addr.sin_addr.s_addr=inet_addr("192.168.76.130"); socklen_t len=sizeof(struct sockaddr_in); while(1) { //3.发送数据 char buff[1024]={0}; scanf("%s",buff); sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&cli_addr,len); //sendto 指向一指定的目的地发送数据 //第一个参数是我们套接字操作符 //第二个参数是要发送的数据 //第三个参数发送的数据长度 //第四个一般为0,如果缓冲区没有数据那么阻塞等待 //第五个指针指向目的套接字的地址 //第六个参数是第五个指针指向的地址长度 // //4.接受来自服务端的数据 memset(buff,0x00,1024);//把缓冲区变成0以防刚刚的数据影响现在新接受的数据 ssize_t r_len=recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&cli_addr,&len); //recvfrom 是通过sock来接受数据的函数 //参数和上边的相同不过这里第六个参数也是指针指向缓冲区的长度 //如果成功返回的是接受的字节数,失败返回-1 if(r_len0) { perror("recvfrom error"); return 0; } printf("server say:%s",buff); } close(sockfd); return 0;}这是客户端的程序,服务端和客户端没有什么区别,不过要注意一个是先发数据,一个是先收数据,不然两个程序会同时阻塞卡住。
//这个是UDP协议聊天程序的服务端#includestdio.h#includestdlib.h#includestring.h#includeunistd.h#includeerrno.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.hint main(){ int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(sockfd0) { perror("socket error"); return -1; } struct sockaddr_in ser_addr; ser_addr.sin_family=AF_INET; ser_addr.sin_port=htons(9000); ser_addr.sin_addr.s_addr=inet_addr("192.168.76.130"); socklen_t len=sizeof(struct sockaddr_in); int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len); //bind 函数将所创建的套接字绑定到一个地址并且赋予一个端口号 //第一个参数是套接字描述符, //第二个参数为要绑定的地址信息 //第三个参数为地址信息的长度。 //返回-1代表绑定失败 if(ret0) { perror("bind error"); close(sockfd); return -1; } while(1) { //接受数据 char buff[1024]={0}; struct sockaddr_in cli_addr; len=sizeof(struct sockaddr_in); ssize_t rlen=recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&cli_addr,&len); if(rlen0) { perror("recvfrom error"); close(sockfd); return -1; } printf("client:%s %d say:%s",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),buff); memset(buff,0x00,1024); scanf("%s",buff); sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&cli_addr,len); } close(sockfd); return -1;}一定是要弄明白哪个先收哪个先发, 不然可能会出现发了那边收不到,只有另一边也发的时候才能收到上一个对方发送的数据。
这里我们还在服务端输出了,与他对话的客户端的ip地址和端口号













