中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

江蘇網(wǎng)站開發(fā)建設(shè)百度客服在線咨詢?nèi)斯し?wù)

江蘇網(wǎng)站開發(fā)建設(shè),百度客服在線咨詢?nèi)斯し?wù),網(wǎng)站建設(shè)過程規(guī)劃和準(zhǔn)備階段,wordpress 投稿 加標(biāo)簽網(wǎng)絡(luò)的基本概念 TCP/IP協(xié)議概述 OSI和TCP/IP模型 socket(套接字) 創(chuàng)建socket 字節(jié)序 字節(jié)序轉(zhuǎn)換函數(shù) 通用地址結(jié)構(gòu) 因特網(wǎng)地址結(jié)構(gòu) IPV4地址族和字符地址間的轉(zhuǎn)換(點(diǎn)分十進(jìn)制->網(wǎng)絡(luò)字節(jié)序) 填寫IPV4地址族結(jié)構(gòu)案例 掌握TCP協(xié)議網(wǎng)絡(luò)基礎(chǔ)編程 相關(guān)函數(shù) …

網(wǎng)絡(luò)的基本概念

在這里插入圖片描述

TCP/IP協(xié)議概述

在這里插入圖片描述

OSI和TCP/IP模型

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

socket(套接字)

在這里插入圖片描述

創(chuàng)建socket

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

字節(jié)序

在這里插入圖片描述

字節(jié)序轉(zhuǎn)換函數(shù)

在這里插入圖片描述

通用地址結(jié)構(gòu)

在這里插入圖片描述

因特網(wǎng)地址結(jié)構(gòu)

在這里插入圖片描述

IPV4地址族和字符地址間的轉(zhuǎn)換(點(diǎn)分十進(jìn)制->網(wǎng)絡(luò)字節(jié)序)

在這里插入圖片描述

填寫IPV4地址族結(jié)構(gòu)案例

在這里插入圖片描述

掌握TCP協(xié)議網(wǎng)絡(luò)基礎(chǔ)編程

在這里插入圖片描述

在這里插入圖片描述

相關(guān)函數(shù)

在這里插入圖片描述
在這里插入圖片描述

特殊bind地址

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

案例1:time

  • 先啟動(dòng)一個(gè)服務(wù)端,客戶鏈接上來之后,服務(wù)端返回一個(gè)系統(tǒng)時(shí)間

  • time_tcp_server.c

#include <stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close\n");/*步驟6:*  關(guān)閉socket* */close(sockfd);exit(1);}
}/*輸出連接上來的客戶端相關(guān)信息* */
void out_addr(struct sockaddr_in *clientaddr)
{// 將端口從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序int port = ntohs(clientaddr->sin_port);char ip[16];memset(ip,0,sizeof(ip));// 網(wǎng)絡(luò)字節(jié)序-> 點(diǎn)分十進(jìn)制inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));printf("client:%s(%d) connected \n",ip,port); 
}
void do_service(int fd)
{// 獲得系統(tǒng)時(shí)間long t = time(0);char *s = ctime(&t);size_t size = strlen(s)*sizeof(char);// 將服務(wù)器端獲得的系統(tǒng)時(shí)間寫到客戶端if(write(fd,s,size)!=size){perror("write  error");}
}
int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}// 綁定一個(gè)信號(hào),ctrl+c 終止服務(wù)端if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){perror("listen error");exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){// 第二個(gè)參數(shù)可以設(shè)置為NULL,如果不想知道客戶端的信息的話int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);if(fd<0){perror("accept error");continue;}/**步驟5:調(diào)用IO函數(shù)和客戶端進(jìn)行雙向的通信*/out_addr(&clientaddr);do_service(fd);/*步驟5:*  關(guān)閉 socket* */ 
![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/d5dcdb3be95a4bbdb7566cb9994daf40.png)
![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/24b23c1c7771411493b1380af83b23af.png)
![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/910db7d627b54bada7cd3b98047f0cf8.png)- time_tcp_client.c```c
#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/int  sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:創(chuàng)建socket* */struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[2]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("connect error");exit(1);}// 步驟3:調(diào)用IO函數(shù),和服務(wù)器進(jìn)行雙向通訊char buffer[1024];memset(buffer,0,sizeof(buffer));size_t size;if((size=read(sockfd,buffer,sizeof(buffer)))<0){perror("read error");}if(write(STDOUT_FILENO,buffer,size)!=size){perror("write error");}// 步驟4:關(guān)閉socketclose(sockfd);return 0;
}

在這里插入圖片描述

自定義協(xié)議

在這里插入圖片描述

  • msg.h
#ifndef __MSG_H__
#define __MSG_H__
#include<sys/types.h>
typedef struct{// 協(xié)議頭部char head[10];// 驗(yàn)證碼char checknum;//協(xié)議體部char buff[512] ;//數(shù)據(jù)
}MSG;
/** 發(fā)送一個(gè)基于自定義協(xié)議的message,發(fā)送的數(shù)據(jù)存放在buff中* */
extern int write_msg(int sockfd,char *buff,size_t len);
/*讀取一個(gè)基于自定義協(xié)議的message。讀取的數(shù)據(jù)存放在buff中* */
extern int read_msg(int sockfd,char *buff,size_t len);#endif
  • msg.c
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<sys/types.h>
#include"msg.h"// 計(jì)算校驗(yàn)碼
static unsigned  char msg_check(Msg *message)
{unsigned char s = 0;for(int i=0;i<sizeof(message->head);i++){s+=message->head[i];}for(int i=0;i<sizeof(message->buff);i++){s+=message->buff[i];}return s;
}/** 發(fā)送一個(gè)基于自定義協(xié)議的message,發(fā)送的數(shù)據(jù)存放在buff中* */int write_msg(int sockfd,char *buff,size_t len)
{Msg message;memset(&message,0,sizeof(message));strcpy(message.head,"iotek2025");memcpy(message.buff,buff,len);message.checknum = msg_check(&message);if(write(sockfd,&message,sizeof(message))!=sizeof(message)){return -1;}
}/*讀取一個(gè)基于自定義協(xié)議的message。讀取的數(shù)據(jù)存放在buff中* */
int read_msg(int sockfd,char *buff,size_t len)
{Msg message;memset(&message,0,sizeof(message));size_t size;if((size=read(sockfd,&message,sizeof(message)))<0){return -1;}else if(size==0){return 0;}// j進(jìn)行校驗(yàn)碼的驗(yàn)證unsigned char s =msg_check(&message);if((s==(unsigned char)message.checknum) && (!strcmp("iotek2025",message.head))){memcpy(buff,message.buff,len);return sizeof(message);}return -1;
}
  • 在服務(wù)端的do_service中增加
void do_service(int fd)
{
//----------------------------------------size_t len;char buff[20];if((len=read(fd,buff,20))<0) // 注意由于客戶端沒有給服務(wù)端寫數(shù)據(jù),所以會(huì)在此阻塞{perror("do_service server read error");}//----------------------------------------// 獲得系統(tǒng)時(shí)間long t = time(0);char *s = ctime(&t);size_t size = strlen(s)*sizeof(char);// 將服務(wù)器端獲得的系統(tǒng)時(shí)間寫到客戶端if(write(fd,s,size)!=size){perror("write  error");}
}

在這里插入圖片描述
在這里插入圖片描述

服務(wù)器并發(fā)性處理

多進(jìn)程模型

  • echo_tcp_server
#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include"msg.h"
int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close\n");/*步驟6:*  關(guān)閉socket* */close(sockfd);exit(1);}if(signo==SIGCHLD){printf("child process dead.....\n");wait(0);}
}/*輸出連接上來的客戶端相關(guān)信息* */
void out_addr(struct sockaddr_in *clientaddr)
{// 將端口從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序int port = ntohs(clientaddr->sin_port);char ip[16];memset(ip,0,sizeof(ip));// 網(wǎng)絡(luò)字節(jié)序-> 點(diǎn)分十進(jìn)制inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));printf("client:%s(%d) connected \n",ip,port); 
}
void do_service(int fd)
{// 和客戶端進(jìn)行讀寫操作(雙向通信)char buff[512];while(1){memset(buff,0,sizeof(buff));printf("start read and write....\n");size_t size;if((size=read_msg(fd,buff,sizeof(buff)))<0){perror("protocal error");break;}else if(size==0){break; // 寫端突然掛了}else{printf("%s\n",buff);if(write_msg(fd,buff,sizeof(buff))<0){if(errno==EPIPE)// 讀端突然關(guān)閉時(shí),類似于管道通信{break;}perror("protocal error");}}}
}
int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}// 綁定一個(gè)信號(hào),ctrl+c 終止服務(wù)端if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}if(signal(SIGCHLD,sig_handler)==SIG_ERR)// 等子進(jìn)程終止發(fā)送的信號(hào){perror("signal sigchild error");exit(1);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){perror("listen error");exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){// 第二個(gè)參數(shù)可以設(shè)置為NULL,如果不想知道客戶端的信息的話int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);if(fd<0){perror("accept error");continue;}/**步驟5:啟動(dòng)子進(jìn)程調(diào)用IO函數(shù)   */pid_t pid = fork();if(pid<0){continue;}else if(pid==0){out_addr(&clientaddr);do_service(fd);/*步驟6:*  關(guān)閉 socket* */close(fd); /// 子進(jìn)程會(huì)復(fù)制父進(jìn)程的fd}else{close(fd); }}return 0;
}
  • echo_tcp_client.c

#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include"msg.h"int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/int  sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:創(chuàng)建socket* */struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[2]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("connect error");exit(1);}// 步驟3:調(diào)用IO函數(shù),和服務(wù)器進(jìn)行雙向通訊char buff[512];size_t size;char * prompt = ">" ;while(1){memset(buff,0,sizeof(buff));write(STDOUT_FILENO,prompt,1);size = read(STDIN_FILENO,buff,sizeof(buff));if(size<0) {continue;}buff[size-1] = '\0';if(write_msg(sockfd,buff,sizeof(buff))<0){perror("write msg error");continue;}else{if(read_msg(sockfd,buff,sizeof(buff))<0){perror("read msg error");continue;}else{printf("%s\n",buff);}}}// 步驟4:關(guān)閉socketclose(sockfd);return 0;
}

在這里插入圖片描述

  • 下面這個(gè)沒有出現(xiàn)
    在這里插入圖片描述

多線程模型

  • ehco_tcp_server_th.c
#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<pthread.h>
#include"msg.h"int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close\n");/*步驟6:*  關(guān)閉socket* */close(sockfd);exit(1);}
}void do_service(int fd)
{// 和客戶端進(jìn)行讀寫操作(雙向通信)char buff[512];while(1){memset(buff,0,sizeof(buff));printf("start read and write....\n");size_t size;if((size=read_msg(fd,buff,sizeof(buff)))<0){perror("protocal error");break;}else if(size==0){break; // 寫端突然掛了}else{printf("%s\n",buff);if(write_msg(fd,buff,sizeof(buff))<0){if(errno==EPIPE)// 讀端突然關(guān)閉時(shí),類似于管道通信{break;}perror("protocal error");}}}
}void out_fd(int fd)
{struct sockaddr_in addr;socklen_t len = sizeof(addr);// 從fd中獲得連接的客戶端的相關(guān)信息if(getpeername(fd,(struct sockaddr*)&addr,&len)<0){perror("getpeername error");return;}char ip[16];memset(ip,0,sizeof(ip));int port = ntohs(addr.sin_port);inet_ntop(AF_INET,&addr.sin_addr.s_addr,ip,sizeof(ip));printf("%16s(%5d) closed\n",ip,port);
}void * th_fn(void *arg)
{int fd = (int)arg;do_service(fd);out_fd(fd);// 輸出客戶端的信息close(fd);return (void*)0;
}int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}// 綁定一個(gè)信號(hào),ctrl+c 終止服務(wù)端if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){perror("listen error");exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);// 設(shè)置線程的分離屬性pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);while(1){// 第二個(gè)參數(shù)可以設(shè)置為NULL,如果不想知道客戶端的信息的話// 主控線程負(fù)責(zé)調(diào)用accept去獲得客戶端的連接 int fd = accept(sockfd,NULL,NULL);if(fd<0){perror("accept error");continue;}/**步驟5:啟動(dòng)子線程調(diào)用IO函數(shù)   */pthread_t th;int err;// 以分離狀態(tài)啟動(dòng)子線程if((err=pthread_create(&th,&attr,th_fn,(void*)fd))!=0){perror("pthread create error");}pthread_attr_destroy(&attr);}return 0;
}

在這里插入圖片描述

I/O多路轉(zhuǎn)換(select)

掌握UDP協(xié)議網(wǎng)絡(luò)基礎(chǔ)編程

在這里插入圖片描述

發(fā)生數(shù)據(jù)

在這里插入圖片描述

接收數(shù)據(jù)

在這里插入圖片描述

  • time_udp_server
#include <stdio.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<signal.h>
#include<time.h>
#include<netdb.h>int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close\n");close(sockfd);exit(1);}}// 輸出客戶端的信息
void out_addr(struct sockaddr_in *clientaddr)
{char ip[16];memset(ip,0,sizeof(ip));inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));int port = ntohs(clientaddr->sin_port);printf("client : %s(%d)\n",ip,port);
}// 和客戶端進(jìn)行通信
void do_service()
{struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);char buffer[1024];memset(buffer,0,sizeof(buffer));// 接受客戶端的數(shù)據(jù)報(bào)文if(recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&clientaddr,&len)<0){perror("recvfrom error");}else{out_addr(&clientaddr);printf("client send into : %s\n",buffer);//向客戶端發(fā)送數(shù)據(jù)報(bào)文long int t = time(0);char * ptr = ctime(&t);size_t size = strlen(ptr)*sizeof(char);if(sendto(sockfd,ptr,size,0,(struct sockaddr*)&clientaddr,len)<0){perror("sendto error");}}}
int main(int argc,char *argv[])
{if(argc<0){printf("usage : %s port \n",argv[0]);exit(1);}if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}/*步驟1:** */sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("sockfd error");exit(1);}int res;int opt = 1;// 設(shè)置套接字選項(xiàng):讓剛才實(shí)現(xiàn)的端口立即啟動(dòng)if((res=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)))<0){perror("setsockopt error");exit(1);}/*步驟2:調(diào)用bind函數(shù)對(duì)socket和地址進(jìn)行綁定* */struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family =  AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1])); // portserveraddr.sin_addr.s_addr = INADDR_ANY; //ipif(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/*步驟3:和客戶端進(jìn)行雙向的數(shù)據(jù)通信* */while(1){do_service();}return 0;
}
  • time_udp_client
   #include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
#include<sys/socket.h>
#include<memory.h>
#include<unistd.h>int main(int argc,char *argv[])
{if(argc<3){printf("usgae : %s ip port \n",argv[0]);exit(1);}/*步驟1:創(chuàng)建socket* */int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket error");exit(1);}/*步驟2:調(diào)用recvfrom和sendto等函數(shù)* 和服務(wù)器進(jìn)行雙向通信* */struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr); //ipchar buffer[1024] = "hello iotek";// 向服務(wù)器端發(fā)送數(shù)據(jù)報(bào)文if(sendto(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("sendto error");exit(1);}else{//接受服務(wù)器發(fā)送的報(bào)文memset(buffer,0,sizeof(buffer));if(recv(sockfd,buffer,sizeof(buffer),0)<0){perror("recv error");exit(1);}else{printf("%s",buffer);}close(sockfd);}return 0;
}

在這里插入圖片描述

  • 在客戶端可以使用connect進(jìn)行連接
    在這里插入圖片描述

這里的connect并沒有和服務(wù)端進(jìn)行三次握手,只是在內(nèi)核中記錄了服務(wù)端的地址信息和端口,所以可以直接使用send不用指出服務(wù)端的地址等信息了。而且調(diào)用connect可以保證只是接受來自服務(wù)端發(fā)送的數(shù)據(jù),不接受其他的信息

  • 多次綁定同一個(gè)端口
    在這里插入圖片描述

在這里插入圖片描述在這里插入圖片描述
第二個(gè)端口起作用
在這里插入圖片描述

域名

在這里插入圖片描述

  • gethostent獲取所有
    在這里插入圖片描述
  • gethostbuname獲取某一個(gè)
    在這里插入圖片描述
    在這里插入圖片描述

在這里插入圖片描述

  • 在Linux中的,位于/etc/hosts
    在這里插入圖片描述
    在這里插入圖片描述

  • gethost.c

#include <stdio.h>
#include<netdb.h>
#include<stdlib.h>
#include<memory.h>void out_addr(struct hostent *h)
{printf("hostbyname: %s\n",h->h_name);printf("addrtype: %s\n",h->h_addrtype==AF_INET ? "IPV4" : "IPV6");char ip[16];memset(ip,0,sizeof(ip));inet_ntop(h->h_addrtype,h->h_addr_list[0],ip,sizeof(ip));printf("ip addrress : %s\n",ip);int i = 0;while(h->h_aliases[i] != NULL){printf("alias : %s \n",h->h_aliases[i]);i++;}
}int main(int argc,char *argv[])
{if(argc<2){printf("usage  %s host \n",argv[0]);exit(1);}struct  hostent *h;h = gethostbyname(argv[1]);if(h!=NULL){out_addr(h);}else{printf("no %s exits\n",argv[1]);}return 0;endhostent();
}

在這里插入圖片描述

注意gethostbyname應(yīng)該避免在多線程下使用。

  • 使用gethostent

#include <stdio.h>
#include<netdb.h>
#include<stdlib.h>
#include<memory.h>void out_addr(struct hostent *h)
{printf("hostbyname: %s\n",h->h_name);printf("addrtype: %s\n",h->h_addrtype==AF_INET ? "IPV4" : "IPV6");char ip[16];memset(ip,0,sizeof(ip));inet_ntop(h->h_addrtype,h->h_addr_list[0],ip,sizeof(ip));printf("ip addrress : %s\n",ip);int i = 0;while(h->h_aliases[i] != NULL){printf("alias : %s \n",h->h_aliases[i]);i++;}
}int main(int argc,char *argv[])
{if(argc<2){printf("usage  %s host \n",argv[0]);exit(1);}struct  hostent *h;while((h=gethostent()) != NULL){if(!strcmp(argv[1],h->h_name)){out_addr(h);exit(0);}else{int i = 0;while(h->h_aliases[i] != NULL){if(!strcmp(argv[1],h->h_aliases[i])){out_addr(h);exit(0);}i++;}}}endhostent();return 0;
}
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
#include<sys/socket.h>
#include<memory.h>
#include<unistd.h>int  is_host(struct hostent *host,char *name)
{if(!strcmp(host->h_name,name))return 1;int i =0;while(host->h_aliases[i] != NULL){if(!strcmp(host->h_aliases[i],name))return 1;i++;}       
}
unsigned int get_ip_by_name(char *name)
{unsigned int ip = 0;struct hostent *host;while((host = gethostent())!=NULL){if(is_host(host,name)){memcpy(&ip,host->h_addr_list[0],4);break;}}endhostent();return ip;
}int main(int argc,char *argv[])
{if(argc<3){printf("usgae : %s ip port \n",argv[0]);exit(1);}/*步驟1:創(chuàng)建socket* */int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket error");exit(1);}/*步驟2:調(diào)用recvfrom和sendto等函數(shù)* 和服務(wù)器進(jìn)行雙向通信* */struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));unsigned int ip = get_ip_by_name(argv[1]);if(ip!=0){serveraddr.sin_addr.s_addr = ip;}else{inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);}//inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr); //ipchar buffer[1024] = "hello iotek";// 向服務(wù)器端發(fā)送數(shù)據(jù)報(bào)文if(sendto(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("sendto error");exit(1);}else{//接受服務(wù)器發(fā)送的報(bào)文memset(buffer,0,sizeof(buffer));if(recv(sockfd,buffer,sizeof(buffer),0)<0){perror("recv error");exit(1);}else{printf("%s",buffer);}close(sockfd);}return 0;
}

在這里插入圖片描述

網(wǎng)絡(luò)高級(jí)編程

廣播

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

套接字選項(xiàng)

在這里插入圖片描述在這里插入圖片描述

TCP不支持廣播,只有UDP才能支持廣播

緩存區(qū)

在這里插入圖片描述

  • receiver.c
#include <stdio.h>
#include<netdb.h>
#include<sys/socket.h>
#include<string.h>
#include<signal.h>
#include<stdlib.h>int sockfd;void sig_handler(int signo)
{if(signo == SIGINT){printf("receiver will exited");close(sockfd);exit(1);}
}int main(int argc,char *argv[])
{if(argc<2){fprintf(stderr,"usage : %s port \n",argv[0]);exit(1);}if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint errro");exit(1);}sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket error");exit(1);}struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[1]));serveraddr.sin_addr.s_addr = INADDR_ANY;if(bind(sockfd,(struct sockadd*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}char buffer[1024];struct sockaddr_in  clientaddr;socklen_t len  = sizeof(clientaddr);while(1){memset(buffer,0,sizeof(buffer));memset(&clientaddr,0,sizeof(clientaddr));if(recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&clientaddr,&len)<0){perror("recvfrom error");exit(1);}else{char ip[16];inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ip,sizeof(ip));int port = ntohs(clientaddr.sin_port); printf("%s{%d}:%s\n",ip,port,buffer);}}return 0;
}
  • broadcast.c
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
#include<sys/socket.h>int main(int argc,char * argv[])
{if(argc<3){fprintf(stderr,"usage: %s ip port\n",argv[0]);exit(1);}int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("sockdt error");exit(1);}int opt = 1;// 采用廣播地址發(fā)送setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family =  AF_INET;serveraddr.sin_port  = htons(atoi(argv[2]));inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);printf("I will broadcast....\n");char *info = "helo yangpipi...";size_t size = strlen(info)*sizeof(char);if(sendto(sockfd,info,size,0,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("sendto error");exit(1);}else{printf("boradcast success\n");}close(sockfd);return 0;

在這里插入圖片描述

多路復(fù)用之fcntl

在這里插入圖片描述
在這里插入圖片描述

  • server.c

#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<pthread.h>
#include<fcntl.h>
#include"vector_fd.h"VectorFD *vfd;
int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close----\n");/*步驟6:*  關(guān)閉socket* */close(sockfd);// 銷毀動(dòng)態(tài)數(shù)組destroy_vector_fd(vfd);exit(1);}
}/**fd對(duì)應(yīng)于某個(gè)連接的客戶端,和某個(gè)連接的客戶端進(jìn)行雙向通信(非阻塞方式)* */
void do_service(int fd)
{// 和客戶端進(jìn)行讀寫操作(雙向通信)char buff[512];while(1){memset(buff,0,sizeof(buff));// 以非阻塞方式讀,讀不到數(shù)據(jù)就返回了,直接服務(wù)于下一個(gè)客戶端,因此不需要判斷size<0的情況size_t size=read(fd,buff,sizeof(buff));if(size==0){char info[] = "client closed";write(STDOUT_FILENO,info,sizeof(info));// 從動(dòng)態(tài)數(shù)組中刪除對(duì)應(yīng)的fdremove_fd(vfd,fd);// 關(guān)閉對(duì)應(yīng)的客戶端的socketclose(fd);}else if(size > 0){write(STDOUT_FILENO,buff,sizeof(buff));if(write(fd,buff,size)<size){if(errno==EPIPE)// 客戶端關(guān)閉連接{perror("write error");remove_fd(vfd,fd);close(fd);}}}}
}void * th_fn(void *arg)
{int i;while(1){// 遍歷動(dòng)態(tài)數(shù)中的socket描述符for(int i = 0;i<vfd->counter;i++){do_service(get_fd(vfd,i));}}return (void*)0;
}void out_addr(struct sockaddr_in *clientaddr)
{char ip[16];memset(ip,0,sizeof(ip));int port = ntohs(clientaddr->sin_port);inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));printf("%s(%d) connected!\n",ip,port);
}
int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}// 綁定一個(gè)信號(hào),ctrl+c 終止服務(wù)端if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){perror("listen error");exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */// 創(chuàng)建放置套接字描述符fd的動(dòng)態(tài)數(shù)組vfd = create_vector_fd();// 設(shè)置線程的分離屬性pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);int err;pthread_t th; if((err=pthread_create(&th,&attr,th_fn,(void*)0))!=0){perror("pthread create error");exit(1);}pthread_attr_destroy(&attr);/** 1) 主控線程獲得客戶端的連接,將新的socket描述符放置到動(dòng)態(tài)數(shù)組中* 2) 啟動(dòng)的子線程負(fù)責(zé)遍歷動(dòng)態(tài)數(shù)組中socket描述符并和對(duì)應(yīng)的客戶端進(jìn)行雙向通信(采用非阻塞方式讀寫)** */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);if(fd<0){perror("accept error");continue;}out_addr(&clientaddr);// 將讀寫方式修改為非阻塞方式int val;fcntl(fd,F_GETFL,&val);val |= O_NONBLOCK;fcntl(fd,F_SETFL,val);        // 將返回新的socket描述符加入到動(dòng)態(tài)數(shù)組中add_fd(vfd,fd);}return 0;
  • client.c
#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/int  sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:創(chuàng)建socket* */struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[2]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("connect error");exit(1);}// 步驟3:調(diào)用IO函數(shù),和服務(wù)器進(jìn)行雙向通訊char buff[512];size_t size;char * prompt = ">" ;while(1){memset(buff,0,sizeof(buff));write(STDOUT_FILENO,prompt,1);size = read(STDIN_FILENO,buff,sizeof(buff));if(size<0) {continue;}buff[size-1] = '\0';if(write(sockfd,buff,sizeof(buff))<0){perror("write msg error");continue;}else{if(read(sockfd,buff,sizeof(buff))<0){perror("read msg error");continue;}else{printf("%s\n",buff);}}}// 步驟4:關(guān)閉socketclose(sockfd);return 0;
}

在這里插入圖片描述

多路復(fù)用之select

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

  • echo_tcp_sever_select.c
#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<pthread.h>
#include<fcntl.h>
#include"vector_fd.h"VectorFD *vfd;
int sockfd;void sig_handler(int signo)
{if(signo==SIGINT){printf("server close----\n");/*步驟6:*  關(guān)閉socket* */close(sockfd);// 銷毀動(dòng)態(tài)數(shù)組destroy_vector_fd(vfd);exit(1);}
}/**fd對(duì)應(yīng)于某個(gè)連接的客戶端,和某個(gè)連接的客戶端進(jìn)行雙向通信(非阻塞方式)* */
void do_service(int fd)
{// 和客戶端進(jìn)行讀寫操作(雙向通信)char buff[512];while(1){memset(buff,0,sizeof(buff));// 以非阻塞方式讀,讀不到數(shù)據(jù)就返回了,直接服務(wù)于下一個(gè)客戶端,因此不需要判斷size<0的情況size_t size=read(fd,buff,sizeof(buff));if(size==0){//char info[] = "client closed";//write(STDOUT_FILENO,info,sizeof(info));printf("client closed\n"); // 這里由于內(nèi)核設(shè)置,所以可以使用帶緩存的IO// 從動(dòng)態(tài)數(shù)組中刪除對(duì)應(yīng)的fdremove_fd(vfd,fd);// 關(guān)閉對(duì)應(yīng)的客戶端的socketclose(fd);}else if(size > 0){//write(STDOUT_FILENO,buff,sizeof(buff));printf("%s\n",buff);if(write(fd,buff,size)<size){if(errno==EPIPE)// 客戶端關(guān)閉連接{perror("write error");remove_fd(vfd,fd);close(fd);}}}}
}/*遍歷出動(dòng)態(tài)數(shù)組中所有的描述符并加入到描述符集set中* 同時(shí)此函數(shù)返回動(dòng)態(tài)數(shù)組中最大的那個(gè)描述符* */
int add_set(fd_set *set)
{FD_ZERO(set); // 清空描述符int max_fd = vfd->fd[0];for(int i = 0;i < vfd->fd[0];i++){int fd = get_fd(vfd,i);if(fd>max_fd){max_fd = fd;}FD_SET(fd,set);//將fd加入到描述符集中}return max_fd;
}
void * th_fn(void *arg)
{struct timeval t;t.tv_sec = 2;t.tv_usec = 0;int n = 0;int maxfd;fd_set set; // 描述符集maxfd = add_set(&set);/*調(diào)用select函數(shù)會(huì)阻塞,委托內(nèi)核去檢查傳入的描述符是否準(zhǔn)備好,* 如有則返回準(zhǔn)備好的描述符,* 超時(shí)則返回0* 第一個(gè)參數(shù)為描述符集中描述符的范圍(最大描述符+1)* */while((n=select(maxfd+1,&set,NULL,NULL,&t))>=0){if(n>0){/*檢測(cè)那些描述符準(zhǔn)備好,并和這些準(zhǔn)備好的描述符對(duì)應(yīng)的客戶端進(jìn)行數(shù)據(jù)的雙向通信* */for(int i=0;i<vfd->counter;i++){int fd = get_fd(vfd,i);if(FD_ISSET(fd,&set)){do_service(fd);}}}//超時(shí)// 重新設(shè)置時(shí)間和清空描述符集t.tv_sec = 2;t.tv_usec = 0;// 重新遍歷動(dòng)態(tài)數(shù)組中最新的描述符放置到描述符集中maxfd = add_set(&set);}
}void out_addr(struct sockaddr_in *clientaddr)
{char ip[16];memset(ip,0,sizeof(ip));int port = ntohs(clientaddr->sin_port);inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));printf("%s(%d) connected!\n",ip,port);
}
int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(0);}// 綁定一個(gè)信號(hào),ctrl+c 終止服務(wù)端if(signal(SIGINT,sig_handler)==SIG_ERR){perror("signal sigint error");exit(1);}/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("sockek error");exit(1);}/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){perror("bind error");exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){perror("listen error");exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */// 創(chuàng)建放置套接字描述符fd的動(dòng)態(tài)數(shù)組vfd = create_vector_fd();// 設(shè)置線程的分離屬性pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);int err;pthread_t th; if((err=pthread_create(&th,&attr,th_fn,(void*)0))!=0){perror("pthread create error");exit(1);}pthread_attr_destroy(&attr);/** 1) 主控線程獲得客戶端的連接,將新的socket描述符放置到動(dòng)態(tài)數(shù)組中* 2) *      a) 啟動(dòng)的子線程調(diào)用select函數(shù)委托內(nèi)核去檢查傳入到select中的描述符是否準(zhǔn)備好*      b) 利用FD_ISSET來找出準(zhǔn)備好的那些描述符并和對(duì)應(yīng)的客戶端進(jìn)行雙向通信(非阻塞)** */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);if(fd<0){perror("accept error");continue;}out_addr(&clientaddr);// 將返回新的socket描述符加入到動(dòng)態(tài)數(shù)組中add_fd(vfd,fd);}return 0;
}

在這里插入圖片描述

守護(hù)進(jìn)程

在這里插入圖片描述

  • 編程步驟
    在這里插入圖片描述
  • 出錯(cuò)處理
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述

#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<pthread.h>
#include<fcntl.h>
#include<syslog.h>
#include<sys/stat.h>
#include"vector_fd.h"VectorFD *vfd;
int sockfd;/**fd對(duì)應(yīng)于某個(gè)連接的客戶端,和某個(gè)連接的客戶端進(jìn)行雙向通信(非阻塞方式)* */
void do_service(int fd)
{// 和客戶端進(jìn)行讀寫操作(雙向通信)char buff[512];while(1){memset(buff,0,sizeof(buff));// 以非阻塞方式讀,讀不到數(shù)據(jù)就返回了,直接服務(wù)于下一個(gè)客戶端,因此不需要判斷size<0的情況size_t size=read(fd,buff,sizeof(buff));if(size==0){char info[] = "client closed\n";syslog(LOG_DEBUG,"client closed");//printf("client closed\n"); // 這里由于內(nèi)核設(shè)置,所以可以使用帶緩存的IO// 從動(dòng)態(tài)數(shù)組中刪除對(duì)應(yīng)的fdremove_fd(vfd,fd);// 關(guān)閉對(duì)應(yīng)的客戶端的socketclose(fd);}else if(size > 0){//write(STDOUT_FILENO,buff,sizeof(buff));// printf("%s\n",buff);syslog(LOG_DEBUG,"%s\n",buff);if(write(fd,buff,size)<size){if(errno==EPIPE)// 客戶端關(guān)閉連接{syslog(LOG_DEBUG,"write:%s\n",strerror(errno));remove_fd(vfd,fd);close(fd);}}}}
}/*遍歷出動(dòng)態(tài)數(shù)組中所有的描述符并加入到描述符集set中* 同時(shí)此函數(shù)返回動(dòng)態(tài)數(shù)組中最大的那個(gè)描述符* */
int add_set(fd_set *set)
{FD_ZERO(set); // 清空描述符int max_fd = vfd->fd[0];for(int i = 0;i < vfd->fd[0];i++){int fd = get_fd(vfd,i);if(fd>max_fd){max_fd = fd;}FD_SET(fd,set);//將fd加入到描述符集中}return max_fd;
}
void * th_fn(void *arg)
{struct timeval t;t.tv_sec = 2;t.tv_usec = 0;int n = 0;int maxfd;fd_set set; // 描述符集maxfd = add_set(&set);/*調(diào)用select函數(shù)會(huì)阻塞,委托內(nèi)核去檢查傳入的描述符是否準(zhǔn)備好,* 如有則返回準(zhǔn)備好的描述符,* 超時(shí)則返回0* 第一個(gè)參數(shù)為描述符集中描述符的范圍(最大描述符+1)* */while((n=select(maxfd+1,&set,NULL,NULL,&t))>=0){if(n>0){/*檢測(cè)那些描述符準(zhǔn)備好,并和這些準(zhǔn)備好的描述符對(duì)應(yīng)的客戶端進(jìn)行數(shù)據(jù)的雙向通信* */for(int i=0;i<vfd->counter;i++){int fd = get_fd(vfd,i);if(FD_ISSET(fd,&set)){do_service(fd);}}}//超時(shí)// 重新設(shè)置時(shí)間和清空描述符集t.tv_sec = 2;t.tv_usec = 0;// 重新遍歷動(dòng)態(tài)數(shù)組中最新的描述符放置到描述符集中maxfd = add_set(&set);}
}void out_addr(struct sockaddr_in *clientaddr)
{char ip[16];memset(ip,0,sizeof(ip));int port = ntohs(clientaddr->sin_port);inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));syslog(LOG_DEBUG,"%s(%d) connected!\n",ip,port);
}
int main(int argc,char *argv[])
{// 參數(shù):服務(wù)器端綁定的端口if(argc<2){printf("usage :%s #port\n",argv[0]);exit(1);}// 守護(hù)進(jìn)程編程的5個(gè)步驟// 步驟1:創(chuàng)建屏蔽字為0umask(0);// 步驟2:調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程,然后父進(jìn)程退出pid_t pid = fork();if(pid>0) exit(0);//步驟3:調(diào)用setsid函數(shù)創(chuàng)建一個(gè)新的會(huì)話setsid();//步驟4:將當(dāng)前工作目錄更改為根目錄chdir("/");//步驟5:關(guān)閉不需要的文件描述符close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);//打開系統(tǒng)日志服務(wù)的一個(gè)連接openlog(argv[0],LOG_PID,LOG_SYSLOG);/* * 步驟1. 創(chuàng)建socket,套接字socket創(chuàng)建在內(nèi)核,是一個(gè)結(jié)構(gòu)體* AF_INET : IPV4* SOCK_STREAM:TCP協(xié)議*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){syslog(LOG_DEBUG,"socket:%s\n",strerror(errno));exit(1);}/** 步驟2:調(diào)用bind函數(shù)將socket和地址(ip和port)進(jìn)行綁定  * */// 專用地址,綁定的時(shí)候在強(qiáng)轉(zhuǎn)為通用地址struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET; // IPV4serveraddr.sin_port = htons(atoi(argv[1]));// 字符串-> 整型,主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序serveraddr.sin_addr.s_addr = INADDR_ANY;//響應(yīng)所有請(qǐng)求if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){// 將日志信息寫入到系統(tǒng)日志文件中(/var/log/syslog)syslog(LOG_DEBUG,"bind:%s\n",strerror(errno));exit(1);}/**步驟3:調(diào)用listen函數(shù)啟動(dòng)監(jiān)聽(指定port監(jiān)聽)通知系統(tǒng)去接受來自客戶端的連接請(qǐng)求將接受到的客戶端連接請(qǐng)求放置到對(duì)應(yīng)的隊(duì)列中第二個(gè)參數(shù):10:隊(duì)列的長(zhǎng)度* */if(listen(sockfd,10)<0){syslog(LOG_DEBUG,"listen:%s\n",strerror(errno));exit(1);}/**步驟4:調(diào)用accept函數(shù),從隊(duì)列中獲得一個(gè)客戶端的請(qǐng)求連接*  并返回一個(gè)新的socket描述符*注意:若沒有客戶端連接,調(diào)用此函數(shù)后會(huì)阻塞直到獲得一個(gè)客戶端的連接* */// 創(chuàng)建放置套接字描述符fd的動(dòng)態(tài)數(shù)組vfd = create_vector_fd();// 設(shè)置線程的分離屬性pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);int err;pthread_t th; if((err=pthread_create(&th,&attr,th_fn,(void*)0))!=0){syslog(LOG_DEBUG,"pthread:%s\n",strerror(errno));exit(1);}pthread_attr_destroy(&attr);/** 1) 主控線程獲得客戶端的連接,將新的socket描述符放置到動(dòng)態(tài)數(shù)組中* 2) *      a) 啟動(dòng)的子線程調(diào)用select函數(shù)委托內(nèi)核去檢查傳入到select中的描述符是否準(zhǔn)備好*      b) 利用FD_ISSET來找出準(zhǔn)備好的那些描述符并和對(duì)應(yīng)的客戶端進(jìn)行雙向通信(非阻塞)** */struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);if(fd<0){syslog(LOG_DEBUG,"accept:%s\n",strerror(errno));continue;}out_addr(&clientaddr);// 將返回新的socket描述符加入到動(dòng)態(tài)數(shù)組中add_fd(vfd,fd);}return 0;
}
http://www.risenshineclean.com/news/52057.html

相關(guān)文章:

  • 網(wǎng)站打不開了什么原因廣東短視頻seo搜索哪家好
  • 濱江網(wǎng)站建設(shè)公司東莞seo建站公司哪家好
  • 黑客網(wǎng)站網(wǎng)站鏈接查詢
  • 黃石做網(wǎng)站公司行業(yè)數(shù)據(jù)統(tǒng)計(jì)網(wǎng)站
  • 淘寶做的網(wǎng)站會(huì)不會(huì)過期十大最免費(fèi)軟件排行榜
  • 一般做哪些外貿(mào)網(wǎng)站寧德市政府
  • 上海找做網(wǎng)站公司友情鏈接官網(wǎng)
  • wordpress 整站移植天津優(yōu)化代理
  • 景觀設(shè)計(jì)方案網(wǎng)站網(wǎng)絡(luò)營(yíng)銷專業(yè)是學(xué)什么的
  • 七牛云做網(wǎng)站今日國(guó)內(nèi)新聞大事
  • 怎么做網(wǎng)站優(yōu)化排名識(shí)別關(guān)鍵詞軟件
  • 通州 網(wǎng)站建設(shè)自己怎樣在百度上做推廣
  • 網(wǎng)上購物商城網(wǎng)站建設(shè)畢業(yè)設(shè)計(jì)全球十大搜索引擎排名
  • 做網(wǎng)站不給源碼程序免費(fèi)建站網(wǎng)站大全
  • 西安網(wǎng)站seo優(yōu)化江東seo做關(guān)鍵詞優(yōu)化
  • 做電影網(wǎng)站用什么空間怎樣做好網(wǎng)絡(luò)營(yíng)銷推廣
  • 超鏈接網(wǎng)站圖片怎么在記事本上做長(zhǎng)沙官網(wǎng)seo收費(fèi)
  • 常州網(wǎng)站推廣多少錢域名備案查詢
  • 百度推廣客服人工電話多少安卓手機(jī)優(yōu)化軟件排名
  • 昆山企業(yè)網(wǎng)站建設(shè)河南關(guān)鍵詞排名顧問
  • 合肥模板建站多少錢網(wǎng)絡(luò)營(yíng)銷方式有哪些
  • 靜態(tài)網(wǎng)站怎么做留言板南京谷歌seo
  • css3網(wǎng)站案例今天最新的新聞?lì)^條
  • 網(wǎng)站開發(fā)與維護(hù)算什么職位成都seo推廣員
  • 游戲動(dòng)漫設(shè)計(jì)專業(yè)網(wǎng)店seo名詞解釋
  • php 做視頻網(wǎng)站免費(fèi)b站推廣網(wǎng)站
  • 做ppt到哪個(gè)網(wǎng)站找圖片十大成功營(yíng)銷策劃案例
  • 登封市建設(shè)局網(wǎng)站廣告制作公司
  • 濟(jì)源做網(wǎng)站的好公司seo線上培訓(xùn)班
  • 大豐做網(wǎng)站的公司付費(fèi)內(nèi)容網(wǎng)站