2.7.3 listen
头文件:#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> 原型:int listen(int sockfd, int backlog); 功能:将套接字设置为被动监听状态 参数: sockfd:文件描述符,socket的返回值 backlog:允许同时连接的客户端的个数,一般设置为5,10 返回值: 成功:0 失败:-1
2.7.4 accept
头文件:#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> 原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 功能:阻塞等待客户端的连接 参数: sockfd:文件描述符,socket的返回值 addr:被填充的网络信息结构体,如果由客户端连接服务器,服务器可以通过这个参数获取客户端的信息 addrlen:addr的大小 返回值: 成功:返回文件描述符 失败:-1
2.7.5 connect
头文件:#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> 原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能:给服务器发送连接请求 参数: sockfd:文件描述符,socket的返回值 addr:要连接的服务器的网络信息结构体,需要客户端自己填充 addrlen:addr的大小 返回值: 成功:返回0 失败:-1
2.8 TCP服务器
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdio.h> #include <errno.h> #include <string.h> #include<arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int main(int argc, char const *argv[]) { //创建套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); //IPV4协议,流式套接字,具体的协议类型 if(-1 == sockfd) { perror("socket"); return -1; } struct sockaddr_in server_addr; //保存服务器的信息 memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8000); server_addr.sin_addr.s_addr = inet_addr("192.168.98.147"); //绑定信息 int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(-1 == ret) { perror("bind"); return -1; } //设置监听队列 ret = listen(sockfd,10); if(-1 == ret) { perror("listen"); return -1; } printf("等待客户端进行连接...、\n"); struct sockaddr_in Client_addr; //用于保存客户端的信息 int length = sizeof(Client_addr); int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length); if(-1 == fd) { perror("accept"); return -1; } printf("接收客户端的连接 %d\n",fd); char buf[32] = {0}; while(1) { ret = recv(fd,buf,sizeof(buf),0); if(-1 == ret) { perror("recv"); return -1; } if(strcmp(buf,"bye") == 0) { break; } printf("%s\n",buf); memset(buf,0 ,sizeof(buf)); } close(fd); close(sockfd); return 0; }
2.9 TCP客户端
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdio.h> #include <errno.h> #include <string.h> #include<arpa/inet.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char const *argv[]) { //创建套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd == -1) { perror("socket"); return -1; } //向服务器发起连接 struct sockaddr_in server_addr; //保存服务器的信息 memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8000); server_addr.sin_addr.s_addr = inet_addr("192.168.98.147"); int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(-1 == ret) { perror("connect"); return -1; } char buf[32] = {0}; while(1) { scanf("%s",buf); ret = send(sockfd,buf,strlen(buf),0); if(-1 == ret) { perror("send"); return -1; } if(strcmp(buf,"bye") == 0) { break; } memset(buf,0,sizeof(buf)); } close(sockfd); return 0; }
2.10 TCP并发服务器
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdio.h> #include <errno.h> #include <string.h> #include<arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <pthread.h> void * ClientHandler(void *arg) { int ret; int fd = *(int *)arg; char buf[32] = {0}; pthread_detach(pthread_self()); //线程结束,自动释放资源 while(1) { ret = recv(fd,buf,sizeof(buf),0); if(-1 == ret) { perror("recv"); return (void *)-1; } else if(0 == ret) { break; //客户端异常退出 } if(strcmp(buf,"bye") == 0) { break; } printf("接收%d客户端 %s\n",fd,buf); memset(buf,0 ,sizeof(buf)); } printf("%d 客户端退出!\n",fd); close(fd); } int main(int argc, char const *argv[]) { //创建套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); //IPV4协议,流式套接字,具体的协议类型 if(-1 == sockfd) { perror("socket"); return -1; } struct sockaddr_in server_addr; //保存服务器的信息 memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8000); server_addr.sin_addr.s_addr = inet_addr("192.168.98.147"); //绑定信息 int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(-1 == ret) { perror("bind"); return -1; } //设置监听队列 ret = listen(sockfd,10); if(-1 == ret) { perror("listen"); return -1; } printf("等待客户端进行连接...、\n"); struct sockaddr_in Client_addr; //用于保存客户端的信息 int length = sizeof(Client_addr); while(1) { int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length); if(-1 == fd) { perror("accept"); return -1; } printf("接收客户端的连接 %d\n",fd); //为每一个客户端创建新的线程 pthread_t tid; ret = pthread_create(&tid,NULL,ClientHandler,&fd); if(ret != 0) { perror("pthread_create"); return -1; } } close(sockfd); return 0; }
#!/bin/bash for ((i=0;i<100;i++)) do ./4-Tcp客户端 & sleep 0.1 done
练习:实现客户端下载服务器所在目录文件
客户端发送要下载的文件名给服务器
服务器判断文件是否存在,将结果告知客户端
如果文件存在,服务器读取文件内容,并发送给客户端
客户端收到文件内容并写入指定的文件
2.11 UDP 网络编程
服务器: 创建套接字 socket 填充服务器网络信息结构体 将套接字和网络信息结构体绑定bind 进行通信 recvfrom /sendto() 客户端: 创建套接字 socket 填充网络信息结构体 进行通信 recvfrom/sendto
函数接口recvfrom/sendto ------recvfrom 1.recvfrom/sendto ------recvfrom 头文件:#include <sys/types.h> #include <sys/socket.h> 原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 功能:接收数据 参数: 前四个和recv一样 src_addr:源的地址,接收谁的数据,他的信息会自动填充到这个参数 addrlen:src_addr的大小 返回值 成功:实际接收的字节数 失败: 返回-1 ------sendto 头文件:#include <sys/types.h> #include <sys/socket.h> 原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 功能:接收数据 参数: 前四个和send一样 dest_addr:目的地址,需要自己指定 addrlen:dest_addr的大小 返回值 成功:发送的字节数 失败: 返回-1 //udp服务器 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #define ERRLOG(errmsg) do{\ perror(errmsg);\ printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\ exit(1);\ }while(0) int main(int argc, char const *argv[]) { int sockfd; //第一步:创建套接字 if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0))) { ERRLOG("socket error"); } struct sockaddr_in serveraddr,clientaddr; socklen_t addrlen = sizeof(serveraddr); //第二步:填充服务器网络信息结构体 serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147"); serveraddr.sin_port = 8888; //第三步:将套接字与服务器网路信息结构体绑定 int ret = bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); if(ret == -1) { ERRLOG("bind"); } //进行通信 char buf[32] = {0}; while(1) { NEXT: if(recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&clientaddr,&addrlen) == -1) { ERRLOG("recvfrom"); } if(strcmp(buf,"bye") == 0) { printf("客户端%s-%d退出了\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port)); goto NEXT; } printf("%s-%d: %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf); } return 0; }
//udp客户端 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #define ERRLOG(errmsg) do{\ perror(errmsg);\ printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\ exit(1);\ }while(0) int main(int argc, char const *argv[]) { int sockfd; //第一步:创建套接字 if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0))) { ERRLOG("socket error"); } struct sockaddr_in serveraddr,clientaddr; socklen_t addrlen = sizeof(serveraddr); //第二步:填充服务器网络信息结构体 serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147"); serveraddr.sin_port = 8888; //进行通信 char buf[32] = {0}; while(1) { scanf("%s",buf); if(sendto(sockfd,buf,32,0,(struct sockaddr *)&serveraddr,addrlen) == -1) { ERRLOG("sendto"); } if(strcmp(buf,"bye") == 0) { printf("客户端退出了\n"); } memset(buf,0,sizeof(buf)); } return 0; }