1 /* 2 * 说明:服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口状态, 3 * 客户端调用socket()初始化后,调用connect() 发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段, 4 * 客户端收到后从connect返回,同时应答一个ACK段,服务器收到后从accecpt()返回。 5 * IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址 6 * IPv6地址用sockaddr_in6结构体表示,包括16位端口号和128位IP地址和一些控制字段 7 * socket API可以接受各种类型的结构体指针做参数 8 * 因为sock API的实现早于ANSI C标准化,那时还没有void *类型,所以这些参数都用 9 * struct sockaddr *表示,所以在传递参数的时候要先转换下: 10 * int bind(int sockfd, const struct sockaddr *addr, 11 * socklen_t addrlen); 12 * 使用:bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)); 13 */ 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <stdio.h> 17 #include <string.h> 18 #include <stdlib.h> 19 #include <arpa/inet.h> 20 #include <unistd.h> 21 #include <ctype.h> 22 23 #define MAX_LINE 80 24 #define SERV_PORT 8000 25 int main() 26 { 27 //初始化客户端和服务端地址,因为是基于IPv4所以用sockaddr_in结构体 28 struct sockaddr_in servaddr, cliaddr; 29 socklen_t cliaddr_len; 30 int listenfd, connfd; 31 char buf[MAX_LINE]; 32 int i, n; 33 //保存地址 34 char str[INET_ADDRSTRLEN]; 35 //分配一个文件描述符:listenfd 36 listenfd = socket(AF_INET, SOCK_STREAM, 0); 37 //如果返回值小于0表示socket分配错误 38 if (listenfd < 0) { 39 perror("socket error\n"); 40 exit(1); 41 } 42 43 //先初始话地址用0填充 44 bzero( &servaddr, sizeof(servaddr) ); 45 //设置地址类型为AF_INET 46 servaddr.sin_family = AF_INET; 47 //设置我网络地址为:INADDR_ANY,这个宏表示本地任意ip地址,htonl表示将32位的长整数从主机字节序转换为网络字节序 48 servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); 49 //设置端口号 50 servaddr.sin_port = htons(SERV_PORT); 51 //绑定文件描述符到服务器地址端口:bind(listenfd, 服务器地址端口), 将sockaddr_in转换为sockaddr 52 bind( listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr) ); 53 54 //使listenfd成为一个监听描述符:listen (listenfd, 连接队列长度) 55 listen(listenfd, 20); 56 printf("Accepting connections ...\n"); 57 while (1) { 58 //阻塞等待客户端链接:connfd = accept(listenfd, 客户端地址端口, 长度) 59 cliaddr_len = sizeof(cliaddr); 60 //accept返回分配新的描述符connfd和客户端通信 61 connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); 62 63 //循环多次:阻塞等待客户端数据请求:read(connfd, buf, size) 64 n = read(connfd, buf, MAX_LINE); 65 //将地址转换为字符串 66 printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); 67 //read返回等待处理客户端请求 68 for (i = 0; i < n; i++) { 69 //将所有字符转换为大写 70 buf[i] = toupper(buf[i]); 71 } 72 write(connfd, buf, n); 73 //关闭 74 close(connfd); 75 } 76 //循环多次结束:发送数据应答write(connfd, buf, size) 77 return 1; 78 }
客户端:
1 /*client.c*/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <unistd.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <arpa/inet.h> 9 10 #define MAX_LINE 80 11 #define SERV_PORT 8000 12 13 int main(int argc, char *argv[]) 14 { 15 struct sockaddr_in servaddr; 16 char buf[MAX_LINE]; 17 int sockfd, n, con; 18 char *str; 19 20 if ( argc != 2 ) { 21 fputs("usage: ./client message\n", stderr); 22 exit(1); 23 } 24 str = argv[1]; 25 26 sockfd = socket(AF_INET, SOCK_STREAM, 0); 27 28 bzero( &servaddr, sizeof(servaddr) ); 29 servaddr.sin_family = AF_INET; 30 inet_pton (AF_INET, "127.0.0.1", &servaddr.sin_addr); 31 servaddr.sin_port = htons(SERV_PORT); 32 33 con = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr) ); 34 if (con < 0) { 35 perror("connect error!\n"); 36 exit(1); 37 } 38 write( sockfd, str, strlen(str)); 39 40 n = read(sockfd, buf, MAX_LINE); 41 printf("Response from server:\n"); 42 write(STDOUT_FILENO, buf, n); 43 printf("\n"); 44 close(sockfd); 45 46 return 1; 47 }
浙公网安备 33010602011771号