1.网络编程和套接字编程
网络编程与C语言中的printf函数和scanf函数以及文件的输入输出相似,本质上也是一种基于I/O的编程方法。之因此这么说,是由于网络编程大可能是基于套接字(socket,网络数据传输的软件设备,操做系统为咱们提供的编程接口)来实现数据的输入输出的。服务器
套接字通讯过程能够类比打电话的过程。电话机能够用来拔打和接听,但对于套接字而言,拔打和接听是有区别的。网络
构建接电话套接字dom
调用socket函数安装电话机socket
#include <sys/socket.h> int socket(int domain, int type, int protocol); -> 成功时返回文件描述符,失败时返回-1
调用bind函数分配电话号码ide
#include <sys/socket.h> int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen); -> 成功时返回0,失败时返回-1
调用listen函数链接电话函数
#include <sys/socket.h> int listen(int sockfd, int backlog); -> 成功时返回0,失败时返回-1
调用accept函数接听电话spa
#include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); -> 成功时返回文件描述符,失败时返回-1
网络编程中接受链接请求的套接字建立过程总结以下:操作系统
1.调用socket函数建立套接字3d
2.调用bind函数分配IP地址和端口号
3.调用了listen函数转换为可接收请求状态
4.调用accept函数受理链接请求
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <arpa/inet.h> 6 #include <sys/socket.h> 7 8 void error_handling(char *message); 9 10 int main(int argc, char *argv[]) 11 { 12 int serv_sock; 13 int clnt_sock; 14 15 struct sockaddr_in serv_addr; 16 struct sockaddr_in clnt_addr; 17 socklen_t clnt_addr_size; 18 19 char message[]="Hello World!"; 20 21 if(argc!=2){ 22 printf("Usage : %s <port>\n", argv[0]); 23 exit(1); 24 } 25 26 serv_sock=socket(PF_INET, SOCK_STREAM, 0); 27 if(serv_sock == -1) 28 error_handling("socket() error"); 29 30 memset(&serv_addr, 0, sizeof(serv_addr)); 31 serv_addr.sin_family=AF_INET; 32 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); 33 serv_addr.sin_port=htons(atoi(argv[1])); 34 35 if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 ) 36 error_handling("bind() error"); 37 38 if(listen(serv_sock, 5)==-1) 39 error_handling("listen() error"); 40 41 clnt_addr_size=sizeof(clnt_addr); 42 clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); 43 if(clnt_sock==-1) 44 error_handling("accept() error"); 45 46 write(clnt_sock, message, sizeof(message)); 47 close(clnt_sock); 48 close(serv_sock); 49 return 0; 50 } 51 52 void error_handling(char *message) 53 { 54 fputs(message, stderr); 55 fputc('\n', stderr); 56 exit(1); 57 }
构建打电话套接字
服务器端建立的套接字又称为服务器端套接字或监听(listening)套接字。而客户端套接字则比较简单,除了建立套接字外,只须要链接过程便可。
客户端发起打电话动做
#include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen); -> 成功时返回0,失败时返回-1
网络编程中发出链接请求的套接字建立过程总结以下:
1.调用socket函数建立套接字
2.调用connect函数发出链接请求
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <arpa/inet.h> 6 #include <sys/socket.h> 7 8 void error_handling(char *message); 9 10 int main(int argc, char* argv[]) 11 { 12 int sock; 13 struct sockaddr_in serv_addr; 14 char message[30]; 15 int str_len; 16 17 if(argc!=3){ 18 printf("Usage : %s <IP> <port>\n", argv[0]); 19 exit(1); 20 } 21 22 sock=socket(PF_INET, SOCK_STREAM, 0); 23 if(sock == -1) 24 error_handling("socket() error"); 25 26 memset(&serv_addr, 0, sizeof(serv_addr)); 27 serv_addr.sin_family=AF_INET; 28 serv_addr.sin_addr.s_addr=inet_addr(argv[1]); 29 serv_addr.sin_port=htons(atoi(argv[2])); 30 31 if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) 32 error_handling("connect() error!"); 33 34 str_len=read(sock, message, sizeof(message)-1); 35 if(str_len==-1) 36 error_handling("read() error!"); 37 38 printf("Message from server: %s \n", message); 39 close(sock); 40 return 0; 41 } 42 43 void error_handling(char *message) 44 { 45 fputs(message, stderr); 46 fputc('\n', stderr); 47 exit(1); 48 }
2.基于Linux的文件操做
在Linux的世界里,socket也被认为是文件的一种,所以在网络数据传输过程当中天然可使用文件I/O相关函数。操做文件或是套接字,首先须要了解什么是文件描述符?文件描述符是一种系统资源,一般是在文件和套接字建立过程由系统分配的一个整数。三个知名文件描述符(标准输入输出及标准错误文件描述符)以下,它们不通过特殊的建立过程,而是伴随系统运行而自动分配的。
下面介绍四个经常使用文件操做函数
//打开文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *path, int flag); -> 成功时返回文件描述符,失败时返回-1 path: 文件名的字符串地址 flag : 文件打开模式信息
其中,文件打开模式经常使用值以下,能够经过位或运算传递多个值
//关闭文件 #include <unistd.h> int close(int fd); -> 成功时返回0,失败时返回-1 fd: 须要关闭的文件或套接字的文件描述符
若调用此函数并传入文件描述符,则关闭相应文件,且此函数同时能够关闭套接字。
//写文件 #include <unistd.h> ssize_t write(int fd, const char *buf, size_t nbytes); -> 成功时返回写入的字节数,失败时返回-1
write函数用于向文件输入数据,固然,经过套接字向其余计算机传输数据亦可以使用该函数。
//读文件 #include <unistd.h> ssize_t read(int fd, char *buf, size_t nbytes); -> 成功时返回读出的字节数(遇到文件结尾则返回0),失败时返回-1
read函数用于从文件读出数据,一样,经过套接字从其余计算机接收数据亦可以使用该函数。
文件描述符与套接字的关系
经过观察下面程序运行结果可知,描述符从3开始从小到大的顺序编号,再次说明了Linux系统中套接字与文件并没有差异。
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/socket.h> int main(void) { int fd1, fd2, fd3; fd1=socket(PF_INET, SOCK_STREAM, 0); fd2=open("test.dat", O_CREAT|O_WRONLY|O_TRUNC); fd3=socket(PF_INET, SOCK_DGRAM, 0); printf("file descriptor 1: %d\n", fd1); printf("file descriptor 2: %d\n", fd2); printf("file descriptor 3: %d\n", fd3); close(fd1); close(fd2); close(fd3); return 0; }
一些思考:
1.INADDR_ANY是什么地址?
2.sockaddr_in与socaddr的关系?
3.为何客户端不须要bind函数将IP信息绑定到套接字?
4.服务端的阻塞函数是什么?
5.listen函数中,监听套接字参数sockfd的做用?与accept返回的套接字参数sockfd之间的关系?
6.listen函数中,参数backlog怎么理解?
以后系列文章中我会结合书中涉及的内容以及本身的理解给出给出参考