文章目錄
- 網絡(續上)
- 1.函數接口
- 2.相關功能實現
- 1.TCP連接
- 2.UDP
- 習題
網絡(續上)
1.函數接口
-
sendto
原型: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:修改套接字調用行為的標志位,通常為0dest_addr:指向一個sockaddr結構體addrlen:指向的結構體的長度 返回值:成功返回實際發送的字節數失敗返回-1
-
recvfrom
原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); 功能:從套接字接收數據,并捕獲發送數據方的源地址 參數:sockfd:socket返回的套接字描述符buf:指向用于存放接收數據的緩沖區的指針len:緩沖區的最大長度flags:控制接受操作的標志位,通常為0src_addr:輸出參數,一般為NULL,不為NULL時,函數將發送方的地址信息填充到這個結構體中addrlen:輸入輸出參數輸入時:必須指向一個整數,大小為src_addr緩沖區的大小輸出時:函數會修改這個整數,并將其設置為src_addr中實際存儲的地址信息的真實長度 返回值:成功返回接收到的字節數失敗返回-1
2.相關功能實現
1.TCP連接
-
客戶端連接
int 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; }
-
服務器連接
int 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
-
客戶端向服務器端發送消息,服務器端回復收到
-
客戶端
int 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; // IPv4seraddr.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; }
-
服務器端
int 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; // IPv4seraddr.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.客戶端向服務器端發送一個文件名,服務器將文件內容打包發給客戶端
-
客戶端
int 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; }
-
服務器端
int 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實現服務器端和客戶端的點對點聊天
-
客戶端
int 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; }
-
服務器端
int 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; }