文章目录
网络(续上)
1.函数接口
-
sendto
tex原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); 功能:向一个指定的目标地址发送数据 参数: sockfd:socket返回的套接字描述符 buf:向包含要发送数据的缓冲区的指针 len:要发送的数据长度 flags:修改套接字调用行为的标志位,通常为0 dest_addr:指向一个sockaddr结构体 addrlen:指向的结构体的长度 返回值: 成功返回实际发送的字节数 失败返回-1
-
recvfrom
tex原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); 功能:从套接字接收数据,并捕获发送数据方的源地址 参数: sockfd:socket返回的套接字描述符 buf:指向用于存放接收数据的缓冲区的指针 len:缓冲区的最大长度 flags:控制接受操作的标志位,通常为0 src_addr:输出参数,一般为NULL,不为NULL时,函数将发送方的地址信息填充到这个结构体中 addrlen:输入输出参数 输入时:必须指向一个整数,大小为src_addr缓冲区的大小 输出时:函数会修改这个整数,并将其设置为src_addr中实际存储的地址信息的真实长度 返回值: 成功返回接收到的字节数 失败返回-1
2.相关功能实现
1.TCP连接
-
客户端连接
cint tcp_client_connect(char const *ip,char const *port){ int fd = socket(AF_INET,SOCK_STREAM,0);//创建一个TCP套接字 if(fd < 0){ perror("socket fail"); return -1; }//创建失败 struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr));//初始化服务器地址结构体 seraddr.sin_family = AF_INET; seraddr.sin_port = htons(atoi(port));//设置端口号 seraddr.sin_addr.s_addr = inet_addr(ip);//输入自己的IP /*尝试连接到服务器,失败返回-1,成功返回套接字描述符*/ if(connect(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){ perror("connect fail"); return -1; } return fd; }
-
服务器连接
cint tcp_accept(char const *ip,char const *port){ int fd = socket(AF_INET,SOCK_STREAM,0);//创建一个TCP套接字 if(fd < 0){ perror("socket fail"); return -1; }//创建失败 res_fd[0] = fd; printf("fd = %d\n",fd); struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr));//初始化服务器地址结构体 seraddr.sin_family = AF_INET; seraddr.sin_port = htons(atoi(port));//设置端口 seraddr.sin_addr.s_addr = inet_addr(ip);//设置IP /*绑定套接字到指定的IP和端口*/ if(bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){ perror("connect fail"); return -1; } /*监听端口,准备接受连接*/ if(listen(fd,5) < 0){ perror("listen fail"); return -1; } /*接受一个客户端的连接,并返回连接的文件描述符*/ int connfd = accept(fd,NULL,NULL); if(connfd < 0){ perror("accept fail"); return -1; } res_fd[1] = connfd; return connfd; }
2.UDP
-
客户端向服务器端发送消息,服务器端回复收到
-
客户端
cint main(){ // 创建 UDP 套接字 int clifd = socket(AF_INET,SOCK_DGRAM,0); if(clifd < 0){ perror("socket fail"); // 创建失败,输出错误信息 return -1; } // 定义并初始化服务器地址结构体 struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; // IPv4 seraddr.sin_port = htons(50000); // 端口号50000,转为网络字节序 seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器IP // 主循环,不断发送和接收消息 while(1){ char buf[1024] = {0}; // 发送缓冲区 // 从标准输入读取一行数据 fgets(buf,sizeof(buf),stdin); // 发送数据到服务器,包含字符串结束符 int ret = sendto(clifd,buf,strlen(buf)+1,0,(const struct sockaddr*)&seraddr,sizeof(seraddr)); char rbuf[1024] = {0}; // 接收缓冲区 // 接收服务器返回的数据 recvfrom(clifd,rbuf,sizeof(rbuf)+1,0,NULL,NULL); // 打印服务器返回的数据 printf("buf = %s\n",rbuf); // 清空接收缓冲区 memset(rbuf,0,sizeof(rbuf)); } return 0; }
-
服务器端
cint main(){ // 创建 UDP 套接字 int serfd = socket(AF_INET,SOCK_DGRAM,0); if(serfd < 0){ perror("socket fail"); // 创建失败,输出错误信息 return -1; } // 定义并初始化服务器地址结构体 struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; // IPv4 seraddr.sin_port = htons(50000); // 端口号50000,转为网络字节序 seraddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡 // 绑定套接字和地址 if(bind(serfd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){ perror("fail to bind"); // 绑定失败,输出错误信息 return -1; } // 主循环,不断接收和回复客户端消息 while(1){ char buf[1024]; // 接收缓冲区 struct sockaddr_in cliaddr; // 客户端地址结构体 socklen_t len = sizeof(cliaddr); // 地址长度 // 接收客户端消息,获取客户端地址 int ret = recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len); // 打印接收到的字节数 printf("ret = %d \n",ret); printf("--------------------------\n"); // 打印客户端IP地址 printf("cliaddr = %s\n",inet_ntoa(cliaddr.sin_addr)); // 打印客户端端口号 printf("cliport = %d\n",ntohs(cliaddr.sin_port)); printf("--------------------------\n"); // 构造回复消息 char sbuf[1024] = {0}; sprintf(sbuf,"recv:%s",buf); // 发送回复消息给客户端 sendto(serfd,sbuf,strlen(sbuf)+1,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)); // 清空发送缓冲区 memset(sbuf,0,sizeof(sbuf)); } return 0; }
-
习题
1.客户端向服务器端发送一个文件名,服务器将文件内容打包发给客户端
-
客户端
cint main(){ int clifd = socket(AF_INET,SOCK_DGRAM,0); if(clifd < 0){ perror("socket fail"); return -1; } struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; seraddr.sin_port = htons(50000); seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); msg_t msg; msg.type = -1; fgets(msg.buf,sizeof(msg.buf),stdin); msg.buf[strlen(msg.buf)-1] = '\0'; sendto(clifd,msg.buf,sizeof(msg.buf),0,(const struct sockaddr*)&seraddr,sizeof(seraddr)); int fd = open(msg.buf,O_WRONLY|O_TRUNC|O_CREAT,0666); if(fd < 0){ perror("fail to open file"); return -1; } int n = 0; while((n = recvfrom(clifd,&msg,sizeof(msg),0,NULL,NULL)) > 0){ if(msg.type == 0){ break; } write(fd,msg.buf,msg.type); memset(&msg,0,sizeof(msg)); } close(fd); close(clifd); return 0; }
-
服务器端
cint main(){ int serfd = socket(AF_INET,SOCK_DGRAM,0); if(serfd < 0){ perror("socket fail"); return -1; } struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; seraddr.sin_port = htons(50000); seraddr.sin_addr.s_addr = INADDR_ANY; if(bind(serfd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){ perror("fail to bind"); return -1; } DIR *dir; struct dirent *dp; msg_t msg; struct sockaddr_in cliaddr; socklen_t len = sizeof(cliaddr); dir = opendir("/home/linux/桌面"); if(dir == NULL){ perror("fail to open dir"); return -1; } recvfrom(serfd,msg.buf,sizeof(msg.buf),0,(struct sockaddr*)&cliaddr,&len); printf("buf = %s\n",msg.buf); while(1){ dp = readdir(dir); if(dp == NULL){ perror("fail to read dir"); return -1; } else if('.' == dp->d_name[0]){ continue; } else if(strcmp(dp->d_name,msg.buf) == 0){ sprintf(msg.buf,"/home/linux/桌面/%s",dp->d_name); int fd = open(msg.buf,O_RDONLY); if(fd < 0){ perror("fail to open file"); return -1; } int n; while((n = read(fd,msg.buf,sizeof(msg.buf))) > 0){ msg.type = n; sendto(serfd,&msg,sizeof(msg),0,(const struct sockaddr*)&cliaddr,sizeof(cliaddr)); } msg.type = 0; sendto(serfd,&msg,sizeof(msg),0,(const struct sockaddr*)&cliaddr,sizeof(cliaddr)); close(fd); break; } } closedir(dir); close(serfd); return 0; }
2.用UDP实现服务器端和客户端的点对点聊天
-
客户端
Cint clifd; struct sockaddr_in seraddr; socklen_t len = sizeof(seraddr); void *thread1(void* arg){ char buf[1024]; while(1){ memset(buf,0,sizeof(buf)); recvfrom(clifd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,&len); if(strcmp(buf,".quit") == 0){ printf("server quit\n"); break; } printf("server say:%s\n",buf); } return NULL; } void *thread2(void* arg){ char buf[1024]; while(1){ memset(buf,0,sizeof(buf)); fgets(buf,sizeof(buf),stdin); if(strcmp(buf,".quit\n") == 0){ break; } sendto(clifd,buf,strlen(buf)+1,0,(struct sockaddr*)&seraddr,sizeof(seraddr)); } return NULL; } int main(){ clifd = socket(AF_INET,SOCK_DGRAM,0); if(clifd < 0){ perror("fail to socket"); return -1; } memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; seraddr.sin_port = htons(50000); seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); pthread_t pid1; pthread_t pid2; void *(*p1)(void*) = thread1; void *(*p2)(void*) = thread2; pthread_create(&pid1,NULL,p1,NULL); pthread_create(&pid2,NULL,p2,NULL); pthread_join(pid1,NULL); pthread_join(pid2,NULL); close(clifd); return 0; }
-
服务器端
cint serfd; struct sockaddr_in seraddr; struct sockaddr_in cliaddr; socklen_t len = sizeof(cliaddr); void *thread1(void* arg){ char buf[1024]; while(1){ memset(buf,0,sizeof(buf)); recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len); if(strcmp(buf,".quit") == 0){ printf("client quit\n"); break; } printf("client say:%s\n",buf); } return NULL; } void *thread2(void* arg){ char buf[1024]; while(1){ memset(buf,0,sizeof(buf)); fgets(buf,sizeof(buf),stdin); if(strcmp(buf,".quit\n") == 0){ break; } sendto(serfd,buf,strlen(buf)+1,0,(struct sockaddr*)&cliaddr,len); } return NULL; } int main(){ serfd = socket(AF_INET,SOCK_DGRAM,0); if(serfd < 0){ perror("fail to socket"); return -1; } memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family = AF_INET; seraddr.sin_port = htons(50000); seraddr.sin_addr.s_addr = INADDR_ANY; if(bind(serfd,(const struct sockaddr*)&seraddr,sizeof(seraddr))< 0){ perror("fail to bind"); return -1; } pthread_t pid1; pthread_t pid2; void *(*p1)(void*) = thread1; void *(*p2)(void*) = thread2; pthread_create(&pid1,NULL,p1,NULL); pthread_create(&pid2,NULL,p2,NULL); pthread_join(pid1,NULL); pthread_join(pid2,NULL); close(serfd); return 0; }