使用到的函数:
// 返回值:读到的字节数,若已到文件尾,返回0;若出错,返回-1 ssize_t read(int fd, void *buf, size_t nbytes); // 返回值:若成功,返回已写的字节数;若出错,返回-1 ssize_t write(int fd, const void *buf, size_t nbytes);
int socket(int socket_family, int socket_type, int protocol); int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// backlog指定系统内核允许在这个监听描述符上排队的最大客户连接数 int listen(int sockfd, int backlog); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
struct sockaddr_in { __uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; };
客户端程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define MAXLINE 4096 int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; if (argc != 2) { perror("Usage: a.out <IPaddress>"); exit(1); } if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(13); /* daytime server */ if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error for %s\n", argv[1]); exit(1); } if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { perror("connect error"); exit(1); } while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; if (fputs(recvline, stdout) == EOF) { perror("fputs error"); exit(1); } } if (n < 0) { perror("read error"); exit(1); } exit(0); }
服务器程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #define MAXLINE 4096 #define LISTENQ 10 int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(13); /* daytime server */ if ( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { perror("bind error"); exit(1); } if ( listen(listenfd, LISTENQ) < 0) { perror("listen error"); exit(1); } for ( ; ; ) { if ( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) < 0) { perror("accept error"); exit(1); } ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); write(connfd, buff, strlen(buff)); close(connfd); } }
PS:
close和shutdown的区别:
(1) close把描述符的引用计数减1,仅在该计数变为0时才关闭套接字。shutdown不管引用计数,直接激发TCP的正常连接终止序列。
(2) close终止读和写两个方向的数据传输,shutdown可以只关闭一个方向。