附:bind()函数的原型如下:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*2.1 填充struct sockaddr_in结构体变量 */ bzero((void*)&mysockaddr, sizeof(mysockaddr)); mysockaddr.sin_family = AF_INET; mysockaddr.sin_port = htons(SERV_PORT);//网络字节序的端口号 mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*2.2 绑定 */ result = bind(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr)); if (result != 0) { perror("bind"); return -1; }
/* server project 2020/8/31 */ #include <cstdio> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> #define SERV_PORT 5050 #define SERV_IP_ADDR "192.168.0.158" //此处IP请自行修改成本机IP int main() { int fd = -1, fd_client; int result = 0; struct sockaddr_in mysockaddr; struct sockaddr_in clientscokaddr; socklen_t clientaddrlen; char botton[64]; /* 1. 创建socket fd */ fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } /*2. 绑定 */ /*2.1 填充struct sockaddr_in结构体变量 */ bzero((void*)&mysockaddr, sizeof(mysockaddr)); mysockaddr.sin_family = AF_INET; mysockaddr.sin_port = htons(SERV_PORT);//网络字节序的端口号 #if 1 //mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR); mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY); #else result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr); if (result != 1) { perror("inet_pton"); return -1; } #endif /*2.2 绑定 */ result = bind(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr)); if (result != 0) { perror("bind"); return -1; } /*3. 调用listen()把主动套接字变成被动套接字 */ result = listen(fd, 5); if (result != 0) { perror("listen"); return -1; } /*4. 阻塞等待客户端连接请求 */ #if 0 bzero((void*)&clientscokaddr, sizeof(clientscokaddr)); fd_client = accept(fd, NULL, NULL); if (-1 == result) { perror("accpet"); return 0; } #else /*优化2:通过程序获取刚建立连接的socket的客户端的IP地址和端口号*/ bzero((void*)&clientscokaddr, sizeof(clientscokaddr)); fd_client = accept(fd, (struct sockaddr*)&clientscokaddr, &clientaddrlen); if (-1 == result) { perror("accpet"); return 0; } char ipv4_addr[16]; if (!inet_ntop(AF_INET, (void*)&clientscokaddr.sin_addr, ipv4_addr, clientaddrlen)) { perror("inet_ntop"); return -1; } printf("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(clientscokaddr.sin_port)); //此处有疑问 为何取到的IP地址和端口号为0.0.0.0:0 #endif FILE* pf = fopen("1.txt", "a+"); if (pf <= 0) { perror("pf"); return -1; } int len = 0,i=0; for (i; i < 3;i++) { result = read(fd_client, botton, 63); if (result < 0) { perror("read"); break; } printf("message is:%s\n", botton); len = strlen(botton); result = fwrite(botton,len,1,pf); if (result != 1) { perror("fwrite"); return -1; } sleep(10); } fclose(pf); close(fd); close(fd_client); return 0; }
/* client project 2020/8/31 */ #include <cstdio> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> #define SERV_PORT 5050 #define SERV_IP_ADDR "192.168.0.158" //此处请自行修改为本机IP int main() { int fd = -1; int result = 0; struct sockaddr_in mysockaddr; char MESSAGE[] = "hELLo wOLd?\n"; /* 1. 创建socket fd */ fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } /*2. 绑定 */ /*2.1 填充struct sockaddr_in结构体变量 */ bzero((void*)&mysockaddr, sizeof(mysockaddr)); mysockaddr.sin_family = AF_INET; mysockaddr.sin_port = htons(SERV_PORT); #if 0 mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR); #else result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr); if (result != 1) { perror("inet_pton"); return -1; } #endif result = connect(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr)); if (result != 0) { perror("connect"); return -1; } printf("Client staring...OK!\n"); while (1) { do { result = write(fd, (void*)MESSAGE, sizeof(MESSAGE)); } while (result < 0 && EINTR == errno); //判断server是否阻塞了连接 详见附录1 sleep(10); } close(fd); return 0; }
Makefile_server: gcc -o server *.cpp -lpthread -Wall Makefile_client: gcc -o client *.cpp -lpthread -Wall
ssize_t write(int fd,const void *buf,size_t nbytes) write函数将buf中的nbytes字节内容写入文件描述符fd。成功时返回写的字节数,失败时返回-1,并设置errno变量。 在网络程序中,当我们向套接字文件描述符写时有俩种可能: 1) write的返回值大于0,表示写了部分或者是全部的数据; 2) 返回的值小于0,此时出现了错误,我们要根据错误类型来处理。 如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接)。 本文中应表示为socket server写入阻塞