和菜鸟一起深入学习国嵌实验之网络编程
1、 tcp程序设计
代码1 server:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333 int main(int argc, char *argv[]) { int sockfd, new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size; int nbytes; char buffer[1024]; //AF_INET: IPV4, SOCK_STREAM: TCP if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Socket error:%s\n\a", strerror(errno)); exit(1); } bzero(&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(portnumber); if(bind(sockfd, (struct sockaddr *) (&server_addr), sizeof(structsockaddr)) == -1) { fprintf(stderr, "Bind error: %s\n\a", strerror(errno)); exit(1); } if(listen(sockfd, 5) == -1) { fprintf(stderr, "Listen error: %s\n\a", strerror(errno)); exit(1); } while(1) { sin_size = sizeof(struct sockaddr_in); if((new_fd = accept(sockfd, (struct sockaddr *)(&client_addr),&sin_size)) == -1) { fprintf(stderr, "Accept error:%s\n\a", strerror(errno)); exit(1); } fprintf(stderr, "Server get connection from %s\n",(char*)inet_ntoa(client_addr.sin_addr)); if((nbytes = read(new_fd, buffer, 1024)) == -1) { fprintf(stderr, "Read Error: %s\n", strerror(errno)); exit(1); } buffer[nbytes] = '\0'; printf("Server received %s\n", buffer); close(new_fd); } close(sockfd); return 0; }
代码2 client:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333 int main(int argc, char *argv[]) { int sockfd; char buffer[1024]; struct sockaddr_in server_addr; struct hostent *host; if(argc != 2) { fprintf(stderr, "Usage: %s hostname \a\n", argv[0]); exit(1); } if((host = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "Gethostname Error:%s\a\n", strerror(errno)); exit(1); } if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Socket Error: %s\a\n", strerror(errno)); exit(1); } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(portnumber); server_addr.sin_addr = *((struct in_addr *) host->h_addr); if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr))== -1) { fprintf(stderr, "Connect Error: %s\a\n", strerror(errno)); exit(1); } printf("Please input char: \n"); fgets(buffer, 1024, stdin); write(sockfd, buffer, strlen(buffer)); close(sockfd); return 0; }
Makefile:
CC = gcc CURTDIR = $(shell pwd) TARGET = tcp_client #TARGET = tcp_server %.o:%.c $(CC)-c $(EXTRAFLAGS) $< -o $@ %.o:%.S $(CC)-c $(EXTRAFLAGS) $< -o $@ .PHONY: all clean $(TARGET): $(TARGET).o $(CC) -o $@ $^ clean: rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$make gcc -c tcp_server.c -o tcp_server.o gcc -o tcp_server tcp_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$ls Makefile tcp_client.c tcp_server tcp_server.c tcp_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$make gcc -c tcp_client.c -o tcp_client.o gcc -o tcp_client tcp_client.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$ls Makefile tcp_client tcp_client.c tcp_client.o tcp_server tcp_server.c tcp_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_client 192.0.4.87 Please input char: hello mytcp eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_client 192.0.4.87 Please input char: I am back! eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.1$./tcp_server Server get connection from 192.0.4.87 Server received hello mytcp Server get connection from 192.0.4.87 Server received I am back!
总结:当没有client连接上时,server程序阻塞在accept函数上,等待连接。当有client连接上来时,阻塞在read函数上,等待读取消息。Client发送一条消息后结束,server读出消息打印,继续等待新的连接
2、 udp程序设计
代码1 server:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333 #define MAX_MSG_SIZE 1024 void udps_respon(int sockfd) { struct sockaddr_in addr; int addrlen, n; char msg[MAX_MSG_SIZE]; while(1) { bzero(msg, sizeof(msg)); addrlen = sizeof(struct sockaddr); n = recvfrom(sockfd, msg, MAX_MSG_SIZE, 0, (struct sockaddr *)&addr,&addrlen); msg[n] = 0; fprintf(stdout, "Server had received %s\n", msg); } } int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in addr; //AF_INET: IPV4, SOCK_DGRAM: UDP if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { fprintf(stderr, "Socket error: %s\n\a", strerror(errno)); exit(1); } bzero(&addr, sizeof(struct sockaddr_in)); addr.sin_family= AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(portnumber); if(bind(sockfd, (struct sockaddr *) (&addr), sizeof(structsockaddr)) == -1) { fprintf(stderr, "Bind error: %s\n\a", strerror(errno)); exit(1); } udps_respon(sockfd); close(sockfd); return 0; }
代码2 client:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333 #define MAX_BUF_SIZE 1024 void udpc_requ(int sockfd, const structsockaddr_in *addr, int len) { char buffer[MAX_BUF_SIZE]; int n; while(1) { printf("Please input char: \n"); fgets(buffer, MAX_BUF_SIZE, stdin); sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr*)addr, len); bzero(buffer, MAX_BUF_SIZE); } } int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in addr; if(argc != 2) { fprintf(stderr, "Usage: %s hostname \a\n", argv[0]); exit(1); } if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { fprintf(stderr, "Socket Error: %s\a\n", strerror(errno)); exit(1); } bzero(&addr,sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(portnumber); if(inet_aton(argv[1], &addr.sin_addr) < 0) { fprintf(stderr, "IP error:%s\n", strerror(errno)); exit(1); } udpc_requ(sockfd, &addr, sizeof(struct sockaddr_in)); close(sockfd); return 0; }
Makefile:
CC = gcc CURTDIR = $(shell pwd) TARGET = udp_client #TARGET = udp_server %.o:%.c $(CC)-c $(EXTRAFLAGS) $< -o $@ %.o:%.S $(CC)-c $(EXTRAFLAGS) $< -o $@ .PHONY: all clean $(TARGET): $(TARGET).o $(CC) -o $@ $^ clean: rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$make gcc -c udp_server.c -o udp_server.o gcc -o udp_server udp_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$make gcc -c udp_client.c -o udp_client.o gcc -o udp_client udp_client.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$./udp_client 192.0.4.87 Please input char: hello myudp Please input char: good-buy Please input char: eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.2$./udp_server Server had received hello myudp Server had received good-buy
总结:当没有client连接上时,server处于阻塞状态,阻塞在recvfrom函数上。当有client连接上来时。Client发送一条消息后结束,server读出消息打印。
3、 并发服务器设计
代码1 server:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <pthread.h> #define portnumber 3333 void *thr_fn(void *arg) { int size, j; char recv_buff[1024]; int *parg = (int *)arg; int new_fd = *parg; printf("new_fd = %d\n", new_fd); while((size = read(new_fd, recv_buff, 1024)) > 0) { if(recv_buff[0] == '@') break; printf("Message from client(%d): %s\n", size, recv_buff); for(j = 0; j < size; j++) { recv_buff[j] = toupper(recv_buff[j]); } write(new_fd, recv_buff, size); memset(recv_buff, 0, sizeof(recv_buff)); } close(new_fd); return NULL; } int main(int argc, char *argv[]) { int listen_sockfd; int com_fd; int i; static char recv_buff[1024]; int len; int port; pthread_t tid; socklen_t clt_addr_len; struct sockaddr_in server_addr; struct sockaddr_in client_addr; if(argc != 2) { printf("Usage: %s port\n", argv[0]); return 1; } port = atoi(argv[1]); if((listen_sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Socket error: %s\n\a", strerror(errno)); exit(1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(port); if(bind(listen_sockfd, (struct sockaddr *) (&server_addr),sizeof(struct sockaddr)) == -1) { fprintf(stderr, "Bind error: %s\n\a", strerror(errno)); close(listen_sockfd); exit(1); } if(listen(listen_sockfd, 5) == -1) { fprintf(stderr, "Listen error: %s\n\a", strerror(errno)); close(listen_sockfd); exit(1); } while(1) { len = sizeof(client_addr); com_fd = accept(listen_sockfd, (struct sockaddr*)&client_addr,&len); if(com_fd < 0) { if(errno == EINTR) { continue; } else { perror("cannot acceptclient connect request\n"); close(listen_sockfd); return 1; } } printf("com_fd = %d\n", com_fd); if((pthread_create(&tid, NULL, thr_fn, &com_fd)) == -1) { perror("pthread_create error"); close(listen_sockfd); close(com_fd); return 1; } } return 0; }
代码2 client:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <sys/un.h> #define portnumber 3333 int main(int argc, char *argv[]) { int connect_fd; int ret; char snd_buf[1024]; int i; int port; int len; static struct sockaddr_in server_addr; if(argc != 3) { fprintf(stderr, "Usage: %s ip \a\n", argv[0]); exit(1); } port = atoi(argv[2]); if((connect_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Socket Error: %s\a\n", strerror(errno)); exit(1); } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(argv[1]); server_addr.sin_port = htons(port); if(connect(connect_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr)) == -1) { fprintf(stderr, "Connect Error: %s\a\n", strerror(errno)); exit(1); } memset(snd_buf, 0, 1024); while(1) { printf("input message: \n"); memset(snd_buf, 0, sizeof(snd_buf)); fgets(snd_buf, 1024, stdin); len = strlen(snd_buf); write(connect_fd, snd_buf, len); len = read(connect_fd, snd_buf, len); if(len > 0) printf("Message from server: %s\n", snd_buf); if(snd_buf[0] == '@') break; } close(connect_fd); return 0; }
Makefile:
CC = gcc CURTDIR = $(shell pwd) #TARGET = thread_client TARGET = thread_server %.o:%.c $(CC)-c $(EXTRAFLAGS) $< -o $@ %.o:%.S $(CC)-c $(EXTRAFLAGS) $< -o $@ .PHONY: all clean $(TARGET): $(TARGET).o $(CC) -o $@ $^ -lpthread clean: rm-rf $(TARGET) $(TARGET).o
运行结果:
eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$make gcc -c thread_server.c -o thread_server.o gcc -o thread_server thread_server.o -lpthread eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$ls Makefile thread_client.c thread_server thread_server.c thread_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$make gcc -c thread_client.c -o thread_client.o gcc -o thread_client thread_client.o -lpthread eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$ls Makefile thread_client thread_client.c thread_client.o thread_server thread_server.c thread_server.o eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222 input message: hello, i am the 1st Message from server: HELLO, I AM THE 1ST input message: @ eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222 input message: hello, i am the 1st, i am back Message from server: HELLO, I AM THE 1ST, IAM BACK input message: @ eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_client 192.0.4.87 2222 input message: hi, i am the 2nd Message from server: HI, I AM THE 2ND input message: @ eastmoon@eastmoon-virtual-machine:~/work/guoqian/4/4.3$./thread_server 2222 com_fd = 4 new_fd = 4 Message from client(20): hello, i am the1st com_fd = 5 new_fd = 5 Message from client(17): hi, i am the 2nd com_fd = 6 new_fd = 6 Message from client(31): hello, i am the1st, i am back
总结:并发服务器由于使用了多线程或者多进程,所以能同事接受多个客户端的连接。循环服务器只有在一个连接断掉之后才能接受另一个连接,因为服务器进程正在执行对客户端的消息收发不能继续循环去接受新的连接。