一、socket编程
网络功能是Uinux/Linux的一个重要特点,有着悠久的历史,因此有一个非常固定的编程套路。
基于TCP的网络编程:
基于连接, 在交互过程中, 服务器和客户端要保持连接, 不能断开。重发一切出错数据、数据验证, 保证数据的正确性、完整性和顺序性,
缺点是消耗的资源比较大。
基于UDP的网络编程:
无连接协议, 在网络交互过程中不保持连接, 只需要在发送数据时连接一下, 不重发、验证数据。优点是资源消耗少, 数据的可靠性完整性
顺序性得不到保证。
二、编程步骤:
服务器:
① 创建socket(套接字) socket()
② 准备通信地址
③ 将创建的socket和通信地址绑定 bind()
④ 监听端口 listen()
⑤ 等待客户端连接 accpet()
⑥ 通信双方收发数据 read()/write()
send()/recv()
⑦ 关闭socket
客户端:
① 创建socket(套接字) socket()
② 准备通信地址
③ 连接服务器 connect()
④ 收发数据 read()/write()
send()/recv()
⑤ 关闭socket
三、API详解
① socket()函数
int socket(domain, type, protocol)
domain:
AF_UNIX/AF_LOCAL/AF_FILE: 本地通信
AF_INET: 网络通信 ipv4
AF_INET6: 网络通信 ipv6
注:如果AF换成PF效果一样
type, 选择通信类型, 主要包括:
SOCK_STREAM: TCP
SOCK_DGRAM : UDP
protocol, 本来应该指定通信协议, 但现在基本废弃, 因为协议已经在前面两个参数指定完成,给0即可
② bind()函数
int bind(int sockfd, struct sockaddr *addr, size)
sockfd: 要绑定的套接字描述符
size: 第二个参数占据的内存空间大小
addr: 涉及三个数据结构struct sockaddr, sockaddr_un, sockaddr_in
sockaddr, 主要用于函数参数, 不负责存储数据
sockaddr_un, 当着本地通信时, 用于本地通信使用的地址 (sys/un.h)
sockaddr_in, 当着网络通信时, 负责存储网络通信的地址数据
struct sockaddr_in {
sin_family; //用于指定协议族, 和socket()的参数保持一致
sin_port; //网络通信使用的端口号
sin_addr; //存储网络通信的ip地址
}
③ htons
④ inet_aton
⑤ listen()函数
int listen(int sockfd, int backlog)
sockfd: 将sockfd参数所标识的套接字为被动模式, 使之可以接受连接请求
backlog: 表示未决连接请求队列的最大长度, 即允许最多有多少个未决连接请求存在。若服务器的未决连接请求已达到该值, 则客户端通过 connect()连接服务器的操作将返回-1,且error为ECONNREFUSED
⑥ accpet()函数
int accpet(sockfd, struct sockaddr* addr, socklen_t *addrlen)
从sockfd参数所标识套接字对应未决连接请求队列中取出的一个连接请求, 同时创建一个新的套接字,用于该连接通信, 返回套接字的描述符
addr和addrlen 用于输出连接请求发起者的地址信息
返回值: 为新创建用于和客户端通信的套接字描述符 失败-1, error
⑦ inet_ntoa
⑧ recv()函数
int recv(int sockfd, buf, len, flags)
flags, 通常取0: 阻塞收取数据
O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息
返回值:
>0, 实际接受数据字节数
-1 , 出错, error
0 , 通信的另一端关闭
⑨ send()函数
int send(int sockfd, buf, len, flags)
flags: 通常取0, 阻塞发送
O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息
⑩ connect()函数
int connect(int sockfd, addr, addr_len)
参数参考bind()
四、TCP示例
1 /******************************* 2 client.c 3 ********************************/ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 #include <netinet/in.h> 11 #include <arpa/inet.h> 12 #define PORT 8888 13 14 int main() 15 { 16 /*1 创建socket*/ 17 int sockfd = socket(AF_INET, SOCK_STREAM, 0); 18 if(sockfd == -1) 19 { 20 perror("socket failed"); 21 exit(-1); 22 } 23 /*2 准备通信地址*/ 24 struct sockaddr_in addr; 25 addr.sin_family = AF_INET; 26 /*设置为服务器进程的端口号*/ 27 addr.sin_port = htons(PORT); 28 /*服务器所在主机IP地址*/ 29 inet_aton("192.168.182.10", &addr.sin_addr); 30 31 /*3 连接服务器*/ 32 int res = connect(sockfd, 33 (struct sockaddr *)&addr, 34 sizeof(addr)); 35 if(res == -1) 36 { 37 perror("connect failed"); 38 exit(-1); 39 } 40 printf("连接服务器成功....\n"); 41 /*4 和服务器交换数据*/ 42 char buf[100] = {0}; 43 char *str = "借点钱可以吗..."; 44 write(sockfd, str, strlen(str)) ; 45 read(sockfd, buf, sizeof(buf)); 46 printf("服务器说:%s\n", buf); 47 48 /*关闭连接*/ 49 close(sockfd); 50 return 0; 51 }
1 /************************************ 2 server.c 3 *************************************/ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <sys/types.h> 10 #include <sys/socket.h> 11 #include <netinet/in.h> 12 #include <arpa/inet.h> 13 #define PORT 8888 14 15 int main() 16 { 17 /*1 创建socket*/ 18 int sockfd = socket(AF_INET, SOCK_STREAM, 0); 19 if(sockfd == -1) 20 { 21 perror("socket failed"); 22 exit(-1); 23 } 24 /*2 准备通信地址*/ 25 struct sockaddr_in addr; 26 addr.sin_family = AF_INET; 27 addr.sin_port = htons(PORT); 28 inet_aton("192.168.182.10", &addr.sin_addr); 29 30 /*3 绑定socket和通信地址*/ 31 int res = bind(sockfd,(struct sockaddr *)&addr, 32 sizeof(addr)); 33 if(res == -1) 34 { 35 perror("bind failed"); 36 exit(-1); 37 } 38 /*4 监听端口*/ 39 res = listen(sockfd, 100); 40 if(res == -1) 41 { 42 perror("listen failed"); 43 exit(-1); 44 } 45 printf("开始监听%d端口,等待客户端连接...\n", 46 PORT); 47 /*5 处理接收客户端的连接请求*/ 48 //用于保存客户端地址信息 49 struct sockaddr_in fromaddr; 50 /*len 取0会是什么效果?*/ 51 socklen_t len = sizeof(fromaddr); 52 int clientfd = accept(sockfd, 53 (struct sockaddr *)&fromaddr, 54 &len); 55 if(clientfd == -1) 56 { 57 perror("accept failed"); 58 exit(-1); 59 } 60 printf("有一个客户端连接到服务器,它是:%s\n", 61 inet_ntoa(fromaddr.sin_addr)); 62 /*6 处理客户端数据*/ 63 char buf[100] = {0}; 64 int count = recv(clientfd, buf, sizeof(buf),0); 65 printf("从客户端读取到%d字节:%s\n", 66 count, buf); 67 char *str = "欢迎你客户端"; 68 send(clientfd, str, strlen(str), 0); 69 /*关闭连接*/ 70 close(clientfd); 71 close(sockfd); 72 return 0; 73 }
五、UDP示例
1 /******************************** 2 UDP_client.c 3 *********************************/ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 #include <netinet/in.h> 11 #include <arpa/inet.h> 12 13 #define PORT 12345 14 int main() 15 { 16 /*1 创建socket*/ 17 int sd = socket(PF_INET, SOCK_DGRAM, 0); 18 if(sd == -1) 19 { 20 perror("socket failed"); 21 exit(-1); 22 } 23 /*2 准备地址*/ 24 struct sockaddr_in addr; 25 addr.sin_family = PF_INET; 26 addr.sin_port = htons(PORT); 27 inet_aton("192.168.182.10", &addr.sin_addr); 28 /*3 进行通信*/ 29 char *str = "借点钱可以吗"; 30 sendto(sd, str, strlen(str), 0, 31 (struct sockaddr *)&addr, 32 sizeof(addr)); 33 char buf[100] = {0}; 34 int len = sizeof(addr); 35 recvfrom(sd, buf, sizeof(buf), 0, 36 (struct sockaddr *) &addr, 37 &len); 38 printf("服务器说:%s\n", buf); 39 close(sd); 40 }
1 /******************************** 2 UDP_server.c 3 *********************************/ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 #include <netinet/in.h> 11 #include <arpa/inet.h> 12 13 #define PORT 12345 14 int main() 15 { 16 /*1 创建socket*/ 17 int sd = socket(PF_INET, SOCK_DGRAM, 0); 18 if(sd == -1) 19 { 20 perror("socket failed"); 21 exit(-1); 22 } 23 /*2 准备地址*/ 24 struct sockaddr_in addr; 25 addr.sin_family = PF_INET; 26 addr.sin_port = htons(PORT); 27 inet_aton("192.168.182.10", &addr.sin_addr); 28 /*3 socket addr 绑定*/ 29 int res = bind(sd, (struct sockaddr *)&addr, 30 sizeof(addr)); 31 if(res == -1) 32 { 33 perror("bind failed"); 34 exit(-1); 35 } 36 /*4 进行通信*/ 37 while(1) 38 { 39 char buf[100] = {0}; 40 struct sockaddr_in fromaddr; 41 int len = sizeof(fromaddr); 42 recvfrom(sd, buf, sizeof(buf), 0, 43 (struct sockaddr *) &fromaddr, 44 &len); 45 printf("从客户端%s接收到数据:%s\n", 46 inet_ntoa(fromaddr.sin_addr), 47 buf); 48 char *str = "没问题,借多少"; 49 sendto(sd, str, strlen(str), 0, 50 (struct sockaddr *)&fromaddr, 51 sizeof(fromaddr)); 52 } 53 close(sd); 54 55 }
来源:http://www.cnblogs.com/jiangson/p/5977601.html