socket编程
读取socket编程
socket接口
-
socket函数 创建套接字的函数
-
函数原型
#include <sys/socket.h> int socket(int domain, int type, int protocol);
-
函数参数
NO. 含义 参数 可选项 1 协议域 domin AF_INET
:IPv4;AF_INET6
:IPv6;AF_LOCAL
:Unix域2 类型 type SOCK_STREAM
:流式套接字;SOCK_DGRAM
:数据报套接字;SOCK_RAW
:原始套接字3 协议 protocol 0
:自动根据type
匹配协议;IPPROTO_TCP
/IPPROTO_UDP
-
返回值
失败返回-1,成功返回套接字的描述符号
-
-
close函数 关闭套接字的函数
-
函数原型
int close(int sockfd) int shutdown(int sockfd,int howto)
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 sockfd 2 关闭方式 howto SHUT_RD
关闭连接的读,SHUT_WDWR
关闭连接的写和读,SHUT_WR
关闭连接的写。
-
-
bind函数 绑定函数
assigning a name to a socket
-
函数原型
#in #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 sockfd 2 地址和端口号 address 3 address缓冲区的大小 address_len -
返回值
成功返回0,失败返回socket_error
-
-
listen函数 监听函数
-
函数原型
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int listen(int sockfd, int backlog);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 sockfd 2 连接的最大上限 backlog -
返回值
成功返回0,失败返回-1。
-
-
connect函数 连接函数
-
函数原型
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 sockfd 2 服务器的socket地址 addr 3 服务器的socket地址的长度 addrlen -
返回值
成功返回0,失败返回-1。
-
-
accept函数 接受函数
-
函数原型
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 sockfd 2 客户端的socket地址 addr 3 客户器的socket地址的长度 addrlen -
返回值
成功返回连接套接字的文件描述符号,失败返回-1。
-
-
write函数 发送数据函数
-
函数原型
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 fd 2 写入的数据 buf 3 写入的数据的长度 len -
返回值
成功返回连接套接字的文件描述符号,失败返回-1。
-
-
read函数 读取数据函数
-
函数原型
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
-
函数参数
NO. 含义 参数 可选项 1 套接字文件描述符号 fd 2 写入的数据 buf 3 读取的数据的长度 len -
返回值
返回值为0代表读到文件的结束,>0代表实际读到的字节数,<0代表出错。
-
socket流程
客户端
打开套接字
连接服务器
写入读取数据
关闭套结字
服务端
打开监听的套结字
设置监听套结字的地址
绑定
监听
打开连接的套结字
读取数据
-
关闭套结字
下面是一个基于tcp的服务器/客户端模型代码,可以实现多个客户端连接服务器并且下载文件。
sever.cpp
void show_info(int connfd){ struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); socklen_t local_addr_len = sizeof(local_addr); getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len); printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port)); struct sockaddr_in peer_addr; bzero(&peer_addr,sizeof(peer_addr)); socklen_t peer_addr_len = sizeof(peer_addr); getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len); printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port)); } void Handle(int connfd){ char buf[BUFSIZ]; for(;;){ bzero(buf,BUFSIZ); ssize_t len; if((len = read(connfd,buf,BUFSIZ-1)) == -1){ perror("read err"); pthread_exit(1); } if(0 == len){ break; } printf("server recv:%s\n",buf); int fd = open(buf,O_RDONLY); if(-1 == fd){ perror("open file err"); // exit(1); } struct stat file_stat; fstat(fd,&file_stat); if(-1 == sendfile(connfd,fd,NULL,file_stat.st_size)){ perror("sendfile err"); // exit(1); } close(fd); } close(connfd); } int main(int argc,char* argv[]){ if(3 != argc){ printf("usage:%s <ip> <#port>\n",argv[0]); return 1; } int listenfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == listenfd){ perror("listenfd open err"); return 1; } printf("socket create OK\n"); int flag = 1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag)); struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = inet_addr(argv[1]); local_addr.sin_port = htons(atoi(argv[2])); if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){ perror("bind err"); return 1; } printf("bind OK\n"); if(-1 == listen(listenfd,10)){ perror("listen err"); return 1; } printf("listen OK\n"); while(true){ struct sockaddr_in remote_addr; bzero(&remote_addr,sizeof(remote_addr)); socklen_t remote_addr_len = sizeof(remote_addr); int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len); if(-1 == connfd){ perror("accept err"); return 1; } printf("accept %s:%d\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port)); show_info(connfd); pthread_t tid; pthread_create(&tid,NULL,reinterpret_cast<void*(*)(void*)>(Handle),reinterpret_cast<void*>(connfd)); pthread_detach(tid); } close(listenfd); }
client.cpp
void show_info(int connfd){ struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); socklen_t local_addr_len = sizeof(local_addr); getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len); printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port)); struct sockaddr_in peer_addr; bzero(&peer_addr,sizeof(peer_addr)); socklen_t peer_addr_len = sizeof(peer_addr); getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len); printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port)); } int main(int argc,char* argv[]){ if(3 != argc){ printf("usage:%s <ip> <#port> \n",argv[0]); return 1; } int connfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == connfd){ perror("socket err"); return 1; } struct sockaddr_in remote_addr; bzero(&remote_addr,sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_addr.s_addr = inet_addr(argv[1]); remote_addr.sin_port = htons(atoi(argv[2])); if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){ perror("connect err"); return 1; } show_info(connfd); char buf[BUFSIZ]; bzero(buf,BUFSIZ); while(fgets(buf,BUFSIZ,stdin) != NULL){ write(connfd,buf,strlen(buf)-1); printf("client send:%s\n",buf); bzero(buf,BUFSIZ); // sendfile(fd,connfd,NULL,); if(-1 == read(connfd,buf,BUFSIZ)){ perror("read err"); return 1; } printf("client recv:%s\n",buf); } close(connfd); }
udp是面向无连接的,函数接口如下图所示:
-