呈现一张基本的socket阻塞式模型,如下图:
服务端(server.c):
1 #include<unistd.h> 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<netinet/in.h> 6 #include<sys/socket.h> 7 #include<sys/types.h> 8 #include<error.h> 9 10 #define ERR_EXIT(m) / 11 do{ / 12 perror(m); / 13 exit(1); / 14 }while(0) 15 16 int 17 main (void) 18 { 19 int sock, conn; 20 if ((sock = socket (PF_INET, SOCK_STREAM, 0)) < 0) 21 ERR_EXIT ("socket"); 22 struct sockaddr_in sockaddr; 23 memset (&sockaddr, 0, sizeof (sockaddr)); 24 sockaddr.sin_family = AF_INET; 25 sockaddr.sin_port = htons (5528); 26 sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); 27 if (bind (sock, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) 28 ERR_EXIT ("Bind"); 29 if (listen (sock, SOMAXCONN) < 0) 30 ERR_EXIT ("Listen"); 31 struct sockaddr_in client; 32 memset (&client, 0, sizeof (client)); 33 socklen_t addrlen = sizeof (client); 34 if ((conn = accept (sock, (struct sockaddr *) &client, &addrlen)) < 0) 35 ERR_EXIT ("Accept"); 36 char sed[1024], recv[1024]; 37 while (fgets (sed, sizeof (sed), stdin) != NULL || 1 == 1) 38 { 39 if (strlen (sed) > 0) 40 write (conn, sed, sizeof (sed)); 41 if (read (conn, recv, sizeof (recv)) > 0) 42 { 43 fputs (recv, stdout); 44 if (strcmp (recv, "exit") == 0) 45 break; 46 write (conn, recv, sizeof (recv)); 47 } 48 else 49 ERR_EXIT ("read..."); 50 } 51 close (conn); 52 close (sock); 53 return 0; 54 }
客户端(client.c):
1 #include<unistd.h> 2 #include<stdio.h> 3 #include<string.h> 4 #include<error.h> 5 #include<netinet/in.h> 6 #include<stdlib.h> 7 #include<sys/socket.h> 8 #include<sys/types.h> 9 10 #define ERR_EXIT( m ) / 11 do{ / 12 perror(m); / 13 exit(1); / 14 }while(0); 15 16 int 17 main (void) 18 { 19 int socketid, conn; 20 21 if ((socketid = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 22 ERR_EXIT ("socket"); 23 24 struct sockaddr_in server_addr; 25 memset (&server_addr, 0, sizeof (server_addr)); 26 27 server_addr.sin_family = AF_INET; 28 server_addr.sin_port = htons (5528); 29 server_addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); 30 if ((conn = 31 connect (socketid, (struct sockaddr *) &server_addr, 32 sizeof (server_addr))) < 0) 33 ERR_EXIT ("connect"); 34 char sendbuf[1024], recivebuf[1024]; 35 while (fgets (sendbuf, sizeof (sendbuf), stdin) != NULL) 36 { 37 write (socketid, sendbuf, sizeof (sendbuf)); 38 read (socketid, recivebuf, sizeof (recivebuf)); 39 fputs (recivebuf, stdout); 40 if (strcmp (recivebuf, "exit") == 0) 41 { 42 ERR_EXIT ("exit"); 43 break; 44 } 45 } 46 close (conn); 47 close (socketid); 48 return 0; 49 }
相关的makefile文件
1 makefile文件: 2 3 .SUFFIXES: .o.c 4 .PHONY: clean 5 .PHONY: start 6 7 CC =gcc 8 SRC =server.c 9 OBJS =$(SRC:.c =.o) 10 BIN = Server 11 12 start: 13 $(CC) -o $(BIN) $(OBJS) 14 15 .o.c: 16 $(CC) -g -Wall $@ -c $< 17 clean: 18 rm -f $(OBJS)
但是上述虽然满足了基本的socket套路,但是当我们关闭服务可执行程序时,在开启就会出现地址被占用,解决此等问题,需再加上一个setsockopt()函数,对齐进行设定。
详细可以去查询man帮助(man setsockopt)
代码:
1 int on = 1; 2 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) 3 { 4 ERR_EXIT ("setsockopt"); 5 } 6 7 8 if (bind (sock, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) 9 ERR_EXIT ("Bind");
客户端和makefile文件和上面一样,只是将socket的服务端,修改为调用进程来进行多并发连接即可!
服务端(server.c):
1 #include<unistd.h> 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<netinet/in.h> 6 #include<sys/socket.h> 7 #include<sys/types.h> 8 #include<error.h> 9 10 #define ERR_EXIT(m) / 11 do{ / 12 perror(m); / 13 exit(1); / 14 }while(0) 15 16 17 void 18 print (int conn){ 19 20 char sed[1024], recv[1024]; 21 while (fgets (sed, sizeof (sed), stdin) != NULL || 1 == 1) 22 { 23 if (strlen (sed) > 0) 24 write (conn, sed, sizeof (sed)); 25 if (read (conn, recv, sizeof (recv)) > 0) 26 { 27 fputs (recv, stdout); 28 if (strcmp (recv, "exit") == 0) 29 break; 30 write (conn, recv, sizeof (recv)); 31 } 32 else 33 ERR_EXIT ("read..."); 34 } 35 close (conn); 36 } 37 38 int 39 main (void) 40 { 41 int sock, conn; 42 if ((sock = socket (PF_INET, SOCK_STREAM, 0)) < 0) 43 ERR_EXIT ("socket"); 44 struct sockaddr_in sockaddr; 45 memset (&sockaddr, 0, sizeof (sockaddr)); 46 sockaddr.sin_family = AF_INET; 47 sockaddr.sin_port = htons (5528); 48 sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); 49 50 int on = 1; 51 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) 52 { 53 ERR_EXIT ("setsockopt"); 54 } 55 56 57 if (bind (sock, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) 58 ERR_EXIT ("Bind"); 59 60 if (listen (sock, SOMAXCONN) < 0) 61 ERR_EXIT ("Listen"); 62 63 struct sockaddr_in client; 64 memset (&client, 0, sizeof (client)); 65 socklen_t addrlen = sizeof (client); 66 pid_t pid ; 67 68 while (1) 69 { 70 if((conn = accept (sock, (struct sockaddr *) &client, &addrlen)) < 0) 71 ERR_EXIT ("Accept"); 72 pid = fork (); 73 if (pid == -1) 74 ERR_EXIT ("fork"); 75 else if (pid == 0){ 76 close (sock); 77 print (conn); 78 } 79 else 80 close (conn); 81 } 82 close (sock); 83 return 0; 84 }