sockaddr_in在头文件#include
参数说明
sin_family主要用于定义是地址族
sin_port主要用来保存端口号
sin_addr主要用来保存IP地址信息
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。
socklen_t是一种数据类型,和int差不多,在32位机下,size_t和int的长度相同,都是32 bits,但在64位机下,size_t(32bits)和int(64 bits)的长度是不一样的,socket编程中的accept函数的第三个参数的长度必须和int的长度相同。于是有了socklen_t类型。
网络字节顺序 (Network Byte Order) NBO
结构体的sin_port和sin_addr都必须是NBO
本机字节顺序 (Host Byte Order) HBO
一般可视化的数字都是HBO
NBO,HBO二者转换
inet_addr() 将字符串点数格式地址转化成无符号长整型(unsigned long s_addr s_addr;)
inet_aton() 将字符串点数格式地址转化成NBO
inet_ntoa () 将NBO地址转化成字符串点数格式
htons() “Host to Network Short”
htonl() “Host to Network Long”
ntohs() “Network to Host Short”
ntohl() “Network to Host Long”
常用的是htons(),inet_addr()正好对应结构体的端口类型和地址类型
htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)
htonl()作用和htons()一样,不过它针对的是32位的(long),而htons()针对的是两个字节,16位的(short)。
inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。
inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)。
在测试过程中遇到以下报错:
Connection reset by peer
TCP链接中常见名词是Client Server, 但是网络连接中经常出现Connection reset by peer
报错分析:
client:客户端
server: 服务端
peer: tcp端。
peer是脱离固定场景的, tcp的任意一端都叫peer.
客户端收到Connection reset by peer代表服务端关闭了链接
服务端收到Connection reset by peer代表客户端关闭了链接
关闭链接的原因可能性就比较多了:
防火墙,路由器等。
解决方法:重启服务端端口
//tcp-server
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define N 128#define ERRLOG(errmsg) do{\perror(errmsg);\printf("%s--%s(%d)\n", __FILE__, __func__, __LINE__);\exit(-1);\}while(0)typedef struct __MSG{char buff[N];int bytes;
}msg_t;int main(int argc, const char *argv[]){if(2 != argc){printf("Usage : %s \n", argv[0]);exit(-1);}//1.创建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){ERRLOG("socket error");}//创建服务器网络信息结构体struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[1]));server_addr.sin_addr.s_addr = htonl(INADDR_ANY);socklen_t addrlen = sizeof(server_addr);//3.将套接字和网络信息结构体进行绑定if(-1 == bind(sockfd, (struct sockaddr *)&server_addr, addrlen)){ERRLOG("bind error");}//4.将服务器的套接字设置成被动监听状态if(-1 == listen(sockfd, 5)){ERRLOG("listen error");}//定义一个结构体,保存客户端的信息struct sockaddr_in client_addr;memset(&server_addr, 0, sizeof(client_addr));//清空socklen_t clientaddrlen = sizeof(client_addr);char buff[N] = {0};int acceptfd = 0;
ACCEPT://5.阻塞等待客户端连接acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &clientaddrlen);if(-1 == acceptfd){ERRLOG("accept error");}printf("客户端 %s:%d 连接到服务器了\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));RENAME:if(-1 == recv(acceptfd, buff, N, 0)){ERRLOG("recv error");}printf("客户端要下载的文件名为:[%s]\n", buff);int fd = open(buff, O_RDONLY);if(-1 == fd){if(errno == ENOENT){printf("文件[%s]不存在\n",buff);if(-1 == send(acceptfd, "****NO EXIST****", N, 0)){perror("send error");goto RENAME;}}else{ERRLOG("open error");}}printf("文件[%s]存在\n",buff);if(-1 == send(acceptfd, "****EXIST****", N, 0)){ERRLOG("send error");}int bytes = 0;msg_t msg;memset(&msg, 0, sizeof(msg));//循环读取文件内容并发送给客户端while((bytes = read(fd, msg.buff, N))>0){msg.bytes = bytes;if(-1 == send(acceptfd, &msg, sizeof(msg), 0)){ERRLOG("send error");}memset(&msg, 0, sizeof(msg));}//发送传输完毕的信息strcpy(msg.buff, "****OVER****");msg.bytes = 0;if(-1 == send(acceptfd, &msg, sizeof(msg), 0)){ERRLOG("send error");}close(acceptfd);goto ACCEPT;close(sockfd);return 0;
}
//tcp-cliaent
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define N 128#define ERRLOG(errmsg) do{\perror(errmsg);\printf("%s--%s(%d)\n", __FILE__, __func__, __LINE__);\exit(-1);\}while(0)typedef struct __MSG{char buff[N];int bytes;
}msg_t;int main(int argc, const char *argv[]){if(3 != argc){printf("Usage : %s \n", argv[0]);exit(-1);}//1.创建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){ERRLOG("socket error");}//创建服务器网络信息结构体struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t addrlen = sizeof(server_addr);//与服务器建立连接if(-1 == connect(sockfd, (struct sockaddr *)&server_addr, addrlen)){ERRLOG("connect error");}char filename[N] = {0};char buff[N] = {0};int fd = 0;
RENAME:printf("请输入要下载的文件:");scanf("%s", filename);//将要下载的文件发送给服务器if(-1 == send(sockfd, filename, N, 0)){ERRLOG("send error");}//接收文件是否存在的信息if(-1 == recv(sockfd, buff, N, 0)){ERRLOG("recv error");}if(0 == strcmp(buff, "****NO EXIST****")){printf("文件不存在\n");goto RENAME;}else if(0 == strcmp(buff, "****EXIST****")){//创建并打开并清空一个文件,准备下载文件内容if(-1 == (fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664))){ERRLOG("open error");}}int bytes = 0;msg_t msg;memset(&msg, 0, sizeof(msg));while(recv(sockfd, &msg, sizeof(msg), 0)>0){if(msg.bytes == 0){break;}if(-1 == write(fd, msg.buff, msg.bytes)){ERRLOG("write error");}memset(&msg, 0, sizeof(msg));}close(fd);printf("文件下载完成\n");//关闭套接字close(sockfd);return 0;
}
//udp-server
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define N 512#define ERRLOG(errmsg) do{\perror(errmsg);\printf("%s--%s(%d)\n", __FILE__, __func__, __LINE__);\exit(-1);\}while(0)typedef struct __MSG{char buff[N];int bytes;
}msg_t;int main(int argc, const char *argv[]){off_t count=0, m,sz;//longlong int n;char buff[N];int acceptfd = 0;if(2 != argc){printf("Usage : %s \n", argv[0]);exit(-1);}//1.创建用户数据报式套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == sockfd){ERRLOG("socket error");}//创建服务器网络信息结构体struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[1]));server_addr.sin_addr.s_addr = htonl(INADDR_ANY);socklen_t addrlen = sizeof(server_addr);//3.将套接字和网络信息结构体进行绑定if(-1 == bind(sockfd, (struct sockaddr *)&server_addr, addrlen)){ERRLOG("bind error");}//定义一个结构体,保存客户端的信息struct sockaddr_in client_addr;memset(&server_addr, 0, sizeof(client_addr));//清空socklen_t clientaddrlen = sizeof(client_addr);#if 0 while(1){//接收数据,如果想要给对方回应,就必须保存对方的网络信息结构体//如果不回应,后两个参数写 NULL 也行if(-1 == recvfrom(sockfd, buff, N, 0, (struct sockaddr *)&client_addr, &clientaddrlen)){ERRLOG("recvfrom error");}printf("%s(%d):%s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buff);//组装应答信息strcat(buff, "--server");if(-1 == sendto(sockfd, buff, N, 0, (struct sockaddr *)&client_addr, clientaddrlen)){ERRLOG("sendto error");}memset(buff, 0, N);}close(sockfd);#endifACCEPT://5.阻塞等待客户端连接acceptfd = recvfrom(sockfd,buff,N,0, (struct sockaddr *)&client_addr, &clientaddrlen);if(-1 == acceptfd ){ERRLOG("recvfrom error");}printf("客户端 %s:%d 连接到服务器了\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));RENAME:printf("客户端要下载的文件名为:[%s]\n", buff);int fd = open(buff, O_RDONLY);if(-1 == fd){if(errno == ENOENT){printf("file [%s] inexistence\n",buff);if(-1 == sendto(sockfd, "****NO EXIST****", N, 0,(struct sockaddr *)&client_addr, clientaddrlen)){perror("send error");goto RENAME;}}else{ERRLOG("open error");}}printf("file [%s] exist\n",buff);if(-1 == sendto(sockfd, "****EXIST****", N, 0,(struct sockaddr *)&client_addr, clientaddrlen)){ERRLOG("send error");}int bytes = 0;msg_t msg;memset(&msg, 0, N);n=read(fd,buff,N);printf("sending.....\n");while(n){if(n == -1){ERRLOG("read fails");}m=sendto(sockfd,buff,N,0,(struct sockaddr*)&client_addr,clientaddrlen);if(m==-1){ERRLOG("send error");}count+=m;bzero(buff,N);n=read(fd,buff,N);}msg.bytes = 0;printf("send over\n");m=sendto(sockfd,buff,0,0,(struct sockaddr*)&client_addr,clientaddrlen);printf("The number of bytes transferred : %lld\n",count);/* //循环读取文件内容并发送给客户端while((bytes = read(fd, msg.buff, N))>0){msg.bytes = bytes;if(-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&client_addr, clientaddrlen)){ERRLOG("send error");}else{}memset(&msg, 0, sizeof(msg));}//发送传输完毕的信息strcpy(msg.buff, "****OVER****");msg.bytes = 0;if(-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&client_addr, clientaddrlen)){ERRLOG("send error");} *///close(acceptfd);//goto ACCEPT;close(sockfd);close(fd);return 0;
}
//udp-client
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define N 512#define ERRLOG(errmsg) do{\perror(errmsg);\printf("%s--%s(%d)\n", __FILE__, __func__, __LINE__);\exit(-1);\}while(0)typedef struct __MSG{char buff[N];int bytes;
}msg_t;int main(int argc, const char *argv[]){off_t count=0, n; // long typechar filename[N];char buff[N];int fd = 0;if(3 != argc){printf("Usage : %s \n", argv[0]);exit(-1);}int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == sockfd){ERRLOG("socket error");}struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t addrlen = sizeof(server_addr);#if 0 while(1){printf("input your msg:");fgets(buff, N, stdin);buff[strlen(buff)-1] = '\0';//清除 \nif(0 == strcmp(buff, "quit")){break;}if(-1 == sendto(sockfd, buff, N, 0, (struct sockaddr *)&server_addr, addrlen)){ERRLOG("sendto error");}if(-1 == recvfrom(sockfd, buff, N, 0, NULL, NULL)){ERRLOG("recvfrom error");}printf("recv:[%s]\n", buff);memset(buff, 0, N);}//关闭套接字close(sockfd);
#endifRENAME:printf("Please enter the file you want to download:");scanf("%s", filename);if(-1 == sendto(sockfd, filename, N, 0,(struct sockaddr *)&server_addr, addrlen)){ERRLOG("send error");}if(-1 == recvfrom(sockfd, buff, N, 0,(struct sockaddr *)&server_addr, &addrlen)){ERRLOG("recv error");}if(0 == strcmp(buff, "****NO EXIST****")){printf("file does not exist\n");goto RENAME;}else if(0 == strcmp(buff, "****EXIST****")){if(-1 == (fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664))){ERRLOG("open error");}}// int bytes = 0;//msg_t msg;bzero(&buff,N);n=recvfrom(sockfd,&buff,N,0,(struct sockaddr *)&server_addr,&addrlen);printf("start receiving.......\n");while(n){if(n==-1){ERRLOG("read fails");}count+=n;write(fd,buff,n);bzero(buff,N);n=recvfrom(sockfd,&buff,N,0,(struct sockaddr *)&server_addr,&addrlen);}printf("file download completes\n");printf("The number of bytes receive : %lld\n",count);/* memset(&msg, 0, sizeof(msg));while(recvfrom(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&server_addr, &addrlen)>0){if(msg.bytes == 0){break;}if(-1 == write(fd, msg.buff, msg.bytes)){ERRLOG("write error");}memset(&msg, 0, sizeof(msg));} */close(fd);close(sockfd);return 0;}