Network socket
Basic skills: two languages, one scripting language. Implement the function first.
Discussion: problems needing attention in cross host transmission.
1. Byte order problem: large end storage: high byte at low address
Small end storage: lower byte at X86 low address
0x00 00 00 05
Da 05 00 00 00
Small 00 00 05
Distinguish between host byte order and network byte order:
Host byte order: host
network byte order: network
Solution: to_ s: htons ,htonl, ntohs,ntohl
2 alignment:
struct
{
int i;
float;
char ch;
}# takes up 12 bytes.
The solution is misalignment.
3. Type length problem:
int
char
Solution: int32_t , uint32_t , int64_t , int8_t , uint8_t
4 what is a socket?
The medium between the protocol layer and the transmission mode.
SOCK_STREAM orderly and reliable (as long as the packet can be received, the data will be guaranteed to be correct) duplex connection based (point-to-point, one-to-one, everyone dedicated) byte stream transmission ().
SOCK_DGRAM is grouped as a unit, connectionless, unreliable, and streaming as opposed.
SOKC_SEQPACKET is safe, reliable, duplex, connection based, orderly and reliable message transmission.
Reporting socket:
Whether the program ape can complete the network program depends on whether the program ape can complete the report socket.
Passive end (running first):
1. Get SOCKET
2. Get the address for SOCKET
3. Receive / send message
4. Close SOCKET
Active end:
1. Get SOCKET
2. Get the address for SOCKET (can be omitted)
3. Receive / send message
4. Close SOCKET
Different protocol families bind different address structures.
socket();
bind();
sendto();
rcvfrom();
inet_pton();
inet_ntop();
setsockopt(int scokfd,int level,int optname,void *optval,socklen_t optlen);
getsockopt();
Basic implementation of datagram socket
Header file h
#ifndef PROTO_H__ #define PROTO_H__ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define RCVPORT "1989" #define NAMESIZE 11 struct msg_st { u_int8_t name[NAMESIZE]; u_int32_t math; u_int32_t chinese; };//Byte misalignment //__attribute_((packed)); #pragma pack() #endif
send out. c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include "proto.h" int main(int argc,char **argv) { int sd; struct msg_st sendbuf; //Remote address, not local address, to whom struct sockaddr_in raddr; if (argc < 2) { fprintf(stderr,"Usage...\n"); exit(1); } sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } // bind(); strcpy(sendbuf.name,"xiaohong"); sendbuf.chinese = htonl(rand()%100); sendbuf.math = htonl(rand()%100); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(RCVPORT)); inet_pton(AF_INET,argv[1],&raddr.sin_addr); if(sendto(sd,&sendbuf,sizeof(sendbuf),0,(void *)&raddr,sizeof(raddr)) < 0) { perror("sendto()"); exit(1); } puts("ok!"); close(sd); exit(0); }
receive. c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include "proto.h" #define IPSTRSIZE 40 int main() { //By default, APV4 supports the implementation of message socket. Write 0, which is equivalent to IPPRPOTO_UDP int sd; struct sockaddr_in laddr,raddr; struct msg_st rcvbuf; socklen_t raddr_len; char ipstr[IPSTRSIZE]; sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } laddr.sin_family = AF_INET; //Host to network, 2 bytes laddr.sin_port = htons(atoi(RCVPORT)); //Convert network IP address to large integer inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr); if (bind(sd,(void *)&laddr,sizeof(laddr)) < 0) { perror("bind()"); exit(1); } /*!!!!!!important*/ raddr_len = sizeof(raddr); while (1) { recvfrom(sd,&rcvbuf,sizeof(rcvbuf),0,(void *)&raddr,&raddr_len); //Network to host, 2 bytes //Large integers are converted to dot fractions, and argc 2 is the address to be converted inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); printf("---MESSAGE FROM %s:%d---\n",ipstr,ntohs(raddr.sin_port)); printf("NAME = %s \n",rcvbuf.name); printf("MATH = %d \n",ntohl(rcvbuf.math)); printf("CHINESE = %d \n",ntohl(rcvbuf.chinese)); } close(sd); exit(0); }
Improved version - send c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include "proto.h" int main(int argc,char **argv) { int sd,size; struct msg_st *sendbufp; //Remote address, not local address, to whom struct sockaddr_in raddr; if (argc < 3) { fprintf(stderr,"Usage...\n"); exit(1); } if (strlen(argv[2])>NAMEMAX) { fprintf(stderr,"Name is too long!\n"); exit(1); } size = sizeof(struct msg_st) + strlen(argv[2]); sendbufp = malloc(size); if (sendbufp == NULL) { perror("malloc()"); exit(1); } sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } strcpy(sendbufp->name,argv[2]); sendbufp->chinese = htonl(rand()%100); sendbufp->math = htonl(rand()%100); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(RCVPORT)); inet_pton(AF_INET,argv[1],&raddr.sin_addr); if(sendto(sd,sendbufp,size,0,(void *)&raddr,sizeof(raddr)) < 0) { perror("sendto()"); exit(1); } puts("ok!"); close(sd); exit(0); }
Improved version - received c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include "proto.h" #define IPSTRSIZE 40 int main() { //By default, APV4 supports the implementation of message socket. Write 0, which is equivalent to IPPRPOTO_UDP int sd,size; struct sockaddr_in laddr,raddr; struct msg_st *rcvbufp; socklen_t raddr_len; char ipstr[IPSTRSIZE]; size = sizeof(struct msg_st) + NAMEMAX -1; rcvbufp = malloc(size); if (rcvbufp == NULL) { perror("malloc()"); exit(1); } sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } laddr.sin_family = AF_INET; //Host to network, 2 bytes laddr.sin_port = htons(atoi(RCVPORT)); //Convert network IP address to large integer inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr); if (bind(sd,(void *)&laddr,sizeof(laddr)) < 0) { perror("bind()"); exit(1); } /*!!!!!!important*/ raddr_len = sizeof(raddr); while (1) { recvfrom(sd,rcvbufp,size,0,(void *)&raddr,&raddr_len); //Network to host, 2 bytes //Large integers are converted to dot fractions, and argc 2 is the address to be converted inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); printf("---MESSAGE FROM %s:%d---\n",ipstr,ntohs(raddr.sin_port)); printf("NAME = %s \n",rcvbufp->name); printf("MATH = %d \n",ntohl(rcvbufp->math)); printf("CHINESE = %d \n",ntohl(rcvbufp->chinese)); } close(sd); exit(0); }
Multipoint communication (broadcast (whole network broadcast, subnet broadcast), multicast/Multicast:
radio broadcast. h
#ifndef PROTO_H__ #define PROTO_H__ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define MTGROUP "224.2.2.2" #define RCVPORT "1989" #define NAMESIZE 11 struct msg_st { u_int8_t name[NAMESIZE]; u_int32_t math; u_int32_t chinese; };//Byte misalignment //__attribute_((packed)); #pragma pack() #endif
Broadcast reception c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <net/if.h> #include "proto.h" #define IPSTRSIZE 40 int main() { //By default, APV4 supports the implementation of message socket. Write 0, which is equivalent to IPPRPOTO_UDP int sd; struct sockaddr_in laddr,raddr; struct msg_st rcvbuf; socklen_t raddr_len; char ipstr[IPSTRSIZE]; sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } struct ip_mreqn mreq; inet_pton(AF_INET,MTGROUP,&mreq.imr_multiaddr); inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); mreq.imr_ifindex = if_nametoindex("eth0"); if (setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0) { perror("setsockopt()"); exit(1); } laddr.sin_family = AF_INET; //Host to network, 2 bytes laddr.sin_port = htons(atoi(RCVPORT)); //Convert network IP address to large integer inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr); if (bind(sd,(void *)&laddr,sizeof(laddr)) < 0) { perror("bind()"); exit(1); } /*!!!!!!important*/ raddr_len = sizeof(raddr); while (1) { recvfrom(sd,&rcvbuf,sizeof(rcvbuf),0,(void *)&raddr,&raddr_len); //Network to host, 2 bytes //Large integers are converted to dot fractions, and argc 2 is the address to be converted inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); printf("---MESSAGE FROM %s:%d---\n",ipstr,ntohs(raddr.sin_port)); printf("NAME = %s \n",rcvbuf.name); printf("MATH = %d \n",ntohl(rcvbuf.math)); printf("CHINESE = %d \n",ntohl(rcvbuf.chinese)); } close(sd); exit(0); }
Broadcast transmission c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <net/if.h> #include <unistd.h> #include <string.h> #include "proto.h" int main(int argc,char **argv) { int sd; struct msg_st sendbuf; struct ip_mreqn mreq; //Remote address, not local address, to whom struct sockaddr_in raddr; sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } //Set to multicast mode and make a change to the current socket property inet_pton(AF_INET,MTGROUP,&mreq.imr_multiaddr); inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); mreq.imr_ifindex = if_nametoindex("eth0"); if(setsockopt(sd,IPPROTO_IP,IP_MULTICAST_IF,&mreq,sizeof(mreq)) < 0) { perror("setsockopt()"); exit(1); } strcpy(sendbuf.name,"xiaohong"); sendbuf.chinese = htonl(rand()%100); sendbuf.math = htonl(rand()%100); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(RCVPORT)); inet_pton(AF_INET,MTGROUP,&raddr.sin_addr); if(sendto(sd,&sendbuf,sizeof(sendbuf),0,(void *)&raddr,sizeof(raddr)) < 0) { perror("sendto()"); exit(1); } puts("ok!"); close(sd); exit(0); }
Implementation of multicast
Multicast transmission c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <net/if.h> #include <unistd.h> #include <string.h> #include "proto.h" int main(int argc,char **argv) { int sd; struct msg_st sendbuf; struct ip_mreqn mreq; //Remote address, not local address, to whom struct sockaddr_in raddr; sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } //Set to multicast mode and make a change to the current socket property inet_pton(AF_INET,MTGROUP,&mreq.imr_multiaddr); inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); mreq.imr_ifindex = if_nametoindex("eth0"); if(setsockopt(sd,IPPROTO_IP,IP_MULTICAST_IF,&mreq,sizeof(mreq)) < 0) { perror("setsockopt()"); exit(1); } strcpy(sendbuf.name,"xiaohong"); sendbuf.chinese = htonl(rand()%100); sendbuf.math = htonl(rand()%100); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(RCVPORT)); inet_pton(AF_INET,MTGROUP,&raddr.sin_addr); if(sendto(sd,&sendbuf,sizeof(sendbuf),0,(void *)&raddr,sizeof(raddr)) < 0) { perror("sendto()"); exit(1); } puts("ok!"); close(sd); exit(0); }
Multicast reception c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <net/if.h> #include "proto.h" #define IPSTRSIZE 40 int main() { //By default, APV4 supports the implementation of message socket. Write 0, which is equivalent to IPPRPOTO_UDP int sd; struct sockaddr_in laddr,raddr; struct msg_st rcvbuf; socklen_t raddr_len; char ipstr[IPSTRSIZE]; sd = socket(AF_INET,SOCK_DGRAM,0); if (sd<0) { perror("socket()"); exit(1); } struct ip_mreqn mreq; inet_pton(AF_INET,MTGROUP,&mreq.imr_multiaddr); inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); mreq.imr_ifindex = if_nametoindex("eth0"); if (setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0) { perror("setsockopt()"); exit(1); } laddr.sin_family = AF_INET; //Host to network, 2 bytes laddr.sin_port = htons(atoi(RCVPORT)); //Convert network IP address to large integer inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr); if (bind(sd,(void *)&laddr,sizeof(laddr)) < 0) { perror("bind()"); exit(1); } /*!!!!!!important*/ raddr_len = sizeof(raddr); while (1) { recvfrom(sd,&rcvbuf,sizeof(rcvbuf),0,(void *)&raddr,&raddr_len); //Network to host, 2 bytes //Large integers are converted to dot fractions, and argc 2 is the address to be converted inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); printf("---MESSAGE FROM %s:%d---\n",ipstr,ntohs(raddr.sin_port)); printf("NAME = %s \n",rcvbuf.name); printf("MATH = %d \n",ntohl(rcvbuf.math)); printf("CHINESE = %d \n",ntohl(rcvbuf.chinese)); } close(sd); exit(0); }
stream socket
Streaming socket Basic Edition
client
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> /* superset of previous */ #include "proto.h" int main(int argc,char**argv) { int sd; struct sockaddr_in raddr; long long stamp; FILE * fp; if (argc < 2) { fprintf(stderr,"Usage...\n"); exit(1); } sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } //bind(); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(SERVERPORT));//Convert Point fractions to large integers inet_pton(AF_INET,argv[1],&raddr.sin_addr); //Connection succeeded if (connect(sd,(void*)&raddr,sizeof(raddr))<0) { perror("connect()"); exit(1); } //File system essence fp = fdopen(sd,"r+"); if (fp == NULL) { perror("fdopen()"); exit(1); } if (fscanf(fp,FMT_STAMP,&stamp)<1) { fprintf(stderr,"Bad format!\n"); } else { fprintf(stdout,"stamp = %lld\n",stamp); } fclose(fp); //rcve(); //close(); exit(0); }
Server side
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> #include "proto.h" #define IPSTRSIZE 40 #define BUFSIZE 1024 /*Every time someone connects with me normally, what I do is to timestamp the current return*/ static void server_job(int sd) { char buf[BUFSIZE]; int len; len = sprintf(buf,FMT_STAMP,(long long)time(NULL)) ; if (send(sd,buf,len,0)<0)//send out { perror("send()"); exit(1); } } int main() { int sd,newsd; char ipstr[IPSTRSIZE]; socklen_t raddr_len; struct sockaddr_in localaddr,rmaddr; sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } int val = 1; /*In order to solve the problem that the used address can be used at any time*/ if(setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))<0) { perror("setsockopt()"); exit(1); } localaddr.sin_family = AF_INET;//protocol family inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr);//Convert the specified IP address into a large integer and store it in localaddr sin_ addr localaddr.sin_port = htons(atoi(SERVERPORT));//port //Bind my port and my IP if (bind(sd,(void*)&localaddr,sizeof(localaddr)) < 0) //connect { perror("bind()"); exit(1); } if(listen(sd,200)<0) //Listening. The second parameter is the size of the full connection queue { perror("listen()"); exit(1); } raddr_len = sizeof(rmaddr); while (1) { //To prevent all previous efforts from being wasted, use newsd newsd = accept(sd,(void *)&rmaddr,&raddr_len); if(newsd<0) //Accept connection { perror("accept()"); exit(1); } inet_ntop(AF_INET,&rmaddr.sin_addr,ipstr,IPSTRSIZE);//Convert large integers into dot strings and store them in ipstr /*Convert the data received on the Internet*/ printf("Client: %s :%d\n",ipstr,ntohs(rmaddr.sin_port)); server_job(newsd); close(newsd); } //It must not be implemented... close(sd); exit(0); }
Protocol end
#ifndef __PROTO_H__ #define __PROTO_H__ #define SERVERPORT "1989" #define FMT_ Stamp '% LLD \ n' / / format of issue timestamp #endif
Streaming socket enhanced
client
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> /* superset of previous */ #include "proto.h" int main(int argc,char**argv) { int sd; struct sockaddr_in raddr; long long stamp; FILE * fp; if (argc < 2) { fprintf(stderr,"Usage...\n"); exit(1); } sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } //bind(); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(SERVERPORT));//Convert Point fractions to large integers inet_pton(AF_INET,argv[1],&raddr.sin_addr); //Connection succeeded if (connect(sd,(void*)&raddr,sizeof(raddr))<0) { perror("connect()"); exit(1); } //File system essence fp = fdopen(sd,"r+"); if (fp == NULL) { perror("fdopen()"); exit(1); } if (fscanf(fp,FMT_STAMP,&stamp)<1) { fprintf(stderr,"Bad format!\n"); } else { fprintf(stdout,"stamp = %lld\n",stamp); } fclose(fp); //rcve(); //close(); exit(0); }
Server side
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> #include "proto.h" #define IPSTRSIZE 40 #define BUFSIZE 1024 /*Every time someone connects with me normally, what I do is to timestamp the current return*/ static void server_job(int sd) { char buf[BUFSIZE]; int len; len = sprintf(buf,FMT_STAMP,(long long)time(NULL)) ; if (send(sd,buf,len,0)<0)//send out { perror("send()"); exit(1); } } int main() { int sd,newsd; pid_t pid; char ipstr[IPSTRSIZE]; socklen_t raddr_len; struct sockaddr_in localaddr,rmaddr; sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } int val = 1; /*In order to solve the problem that the used address can be used at any time*/ if(setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))<0) { perror("setsockopt()"); exit(1); } localaddr.sin_family = AF_INET;//protocol family inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr);//Convert the specified IP address into a large integer and store it in localaddr sin_ addr localaddr.sin_port = htons(atoi(SERVERPORT));//port //Bind my port and my IP if (bind(sd,(void*)&localaddr,sizeof(localaddr)) < 0) //connect { perror("bind()"); exit(1); } if(listen(sd,200)<0) //Listening. The second parameter is the size of the full connection queue { perror("listen()"); exit(1); } raddr_len = sizeof(rmaddr); while (1) { //To prevent all previous efforts from being wasted, use newsd newsd = accept(sd,(void *)&rmaddr,&raddr_len); if(newsd<0) //Accept connection { perror("accept()"); exit(1); } //The parent process accept s to the child process pid = fork(); if (pid<0) { perror("fork()"); exit(1); } if (pid == 0) //Subprocess work { //Child processes only use newsd, not sd close(sd); inet_ntop(AF_INET,&rmaddr.sin_addr,ipstr,IPSTRSIZE);//Convert large integers into dot strings and store them in ipstr /*Convert the data received on the Internet*/ printf("Client: %s :%d\n",ipstr,ntohs(rmaddr.sin_port)); server_job(newsd); close(newsd); exit(0); //Run after work } //The parent process uses only sd instead of newsd close(newsd); } //It must not be implemented... close(sd); exit(0); }
Protocol end
#ifndef __PROTO_H__ #define __PROTO_H__ #define SERVERPORT "1989" #define FMT_ Stamp '% LLD \ n' / / format of issue timestamp #endif
Static process pool
client
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> /* superset of previous */ #include "proto.h" int main(int argc,char**argv) { int sd; struct sockaddr_in raddr; long long stamp; FILE * fp; if (argc < 2) { fprintf(stderr,"Usage...\n"); exit(1); } sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } //bind(); raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(SERVERPORT));//Convert Point fractions to large integers inet_pton(AF_INET,argv[1],&raddr.sin_addr); //Connection succeeded if (connect(sd,(void*)&raddr,sizeof(raddr))<0) { perror("connect()"); exit(1); } //File system essence fp = fdopen(sd,"r+"); if (fp == NULL) { perror("fdopen()"); exit(1); } if (fscanf(fp,FMT_STAMP,&stamp)<1) { fprintf(stderr,"Bad format!\n"); } else { fprintf(stdout,"stamp = %lld\n",stamp); } fclose(fp); //rcve(); //close(); exit(0); }
Server side
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <netinet/ip.h> #include "proto.h" #define IPSTRSIZE 40 #define BUFSIZE 1024 #define PROCNUM 4 static void server_loop(int sd); /*Every time someone connects with me normally, what I do is to timestamp the current return*/ static void server_job(int sd) { char buf[BUFSIZE]; int len; len = sprintf(buf,FMT_STAMP,(long long)time(NULL)) ; if (send(sd,buf,len,0)<0)//send out { perror("send()"); exit(1); } } int main() { int sd,i; struct sockaddr_in localaddr; pid_t pid; sd = socket(AF_INET,SOCK_STREAM,0/*Default IPPROTO_TCP,IPPRORO_SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } int val = 1; /*In order to solve the problem that the used address can be used at any time*/ if(setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))<0) { perror("setsockopt()"); exit(1); } localaddr.sin_family = AF_INET;//protocol family inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr);//Convert the specified IP address into a large integer and store it in localaddr sin_ addr localaddr.sin_port = htons(atoi(SERVERPORT));//port //Bind my port and my IP if (bind(sd,(void*)&localaddr,sizeof(localaddr)) < 0) //connect { perror("bind()"); exit(1); } if(listen(sd,200)<0) //Listening. The second parameter is the size of the full connection queue { perror("listen()"); exit(1); } for (i = 0; i < PROCNUM; i++) { pid = fork(); if (pid<0) { perror("fork()"); exit(1); } if (pid == 0) { server_loop(sd);//Subprocesses work forever exit(0); } for (i = 0; i < PROCNUM; i++) { wait(NULL); } close(sd); exit(0); } } static void server_loop(int sd) { socklen_t raddr_len; struct sockaddr_in localaddr,rmaddr; int newsd; char ipstr[IPSTRSIZE]; raddr_len = sizeof(rmaddr); while (1) { //To prevent all previous efforts from being wasted, use newsd newsd = accept(sd,(void *)&rmaddr,&raddr_len); if(newsd<0) //Accept connection { perror("accept()"); exit(1); } inet_ntop(AF_INET,&rmaddr.sin_addr,ipstr,IPSTRSIZE);//Convert large integers into dot strings and store them in ipstr /*Convert the data received on the Internet*/ printf("[%d] Client: %s :%d\n",getpid(),ipstr,ntohs(rmaddr.sin_port)); server_job(newsd); close(newsd); } //It must not be implemented... close(sd); }
Protocol end
#ifndef __PROTO_H__ #define __PROTO_H__ #define SERVERPORT "1989" #define FMT_ Stamp '% LD \ n' / / format of issue timestamp #endif
Dynamic process pool
The difference from static thread pool is only on the server side
Server side (difficulty *****)
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <signal.h> #include <time.h> #include <errno.h> #include <sys/mman.h> #include <unistd.h> #include <arpa/inet.h> #include "proto.h" //Minimum number of free #define MINSPARESERVER 5 #define MAXSPARESERVER 10 #define MAXCLIENTS 20 #define SIG_ Notify sigusr2 / / reserved signals defining behavior #define LINEBUFSIZE 80 #define IPSTRSIZE 40 #define BUFSIZE 1024 enum { STATE_IDEL = 0, STATE_BUSY }; struct sever_st { pid_t pid; int state; //int reuse; }; //Define a dynamic thread pool and store it on the heap static struct sever_st *serverpool; static int idle_count = 0,busy_count = 0; static int sd; static void server_job(int pos) { int ppid,client_sd,len; time_t stamp; char linebuf[LINEBUFSIZE]; char ipstr[IPSTRSIZE]; ppid = getppid(); socklen_t raddr_len; struct sockaddr_in raddr; while (1) { serverpool[pos].state = STATE_IDEL; kill(ppid,SIG_NOTIFY); //Notify the parent process to take a look client_sd = accept(sd,(void *)&raddr,&raddr_len); if (client_sd<0) { if (errno != EINTR || errno != EAGAIN) { perror("accept()"); exit(1); } } //Set the current status to busy serverpool[pos].state = STATE_BUSY; kill(ppid,SIG_NOTIFY); //Notify parent process to see //inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); //Test procedure //printf("[%d]client:%s:%d",getpid(),ipstr,ntohs(raddr.sin_port)); stamp = time(NULL); //Write to string len = snprintf(linebuf,LINEBUFSIZE,FMT_STAMP,stamp); send(client_sd,linebuf,len,0); /* if error */ sleep(3); close(client_sd); } } //Work code static int add_1_server(void) { int slot; pid_t pid; //Maximum reached if (idle_count + busy_count >= MAXCLIENTS) return -1; for (slot = 0; slot < MAXCLIENTS; slot++) if (serverpool[slot].pid == -1) break; serverpool[slot].state = STATE_IDEL; pid = fork(); if (pid<0) { perror("fork()"); exit(1); } if (pid == 0) { server_job(slot);//Subprocesses work forever exit(0); } else { serverpool[slot].pid = pid; idle_count ++; } return 0; } static int del_1_server(void) { int i; if (idle_count == 0) return -1; for ( i = 0; i < MAXCLIENTS; i++) { if (serverpool[i].pid != -1 && serverpool[i].state == STATE_IDEL) { kill(serverpool[i].pid,SIGTERM);//Kill the process serverpool[i].pid = -1; idle_count --; break; } } return 0; } static void usr2_handlers(int s) { return; } //Traversal state pool static int scanf_pool(void) { int i,busy = 0,idle = 0; for ( i = 0; i < MAXCLIENTS; i++) { if (serverpool[i].pid == -1) continue; if (kill(serverpool[i].pid,0))//Check whether the i-space pid of serverpool exists { serverpool[i].pid = -1; continue; } if (serverpool[i].pid == STATE_IDEL)//Check whether the i-space pid of serverpol exists { idle++; } else if (serverpool[i].pid == STATE_BUSY) { busy++; } else { fprintf(stderr,"Unknown statae.\n"); //_exit(1); abort(); } } idle_count = idle; busy_count = busy; return 0; } int main() { int sd,i,len,val = 1; struct sockaddr_in localaddr; pid_t pid; struct sigaction sa,osa; sigset_t set,oset; //Let the child process die by itself, sa.sa_handler = SIG_IGN;//This signal is used to notify the parent process of blocking to collect the corpse, so ignore it first to prevent the parent process from collecting the corpse sigemptyset(&sa.sa_mask);//No signals use the same signal processing function sa.sa_flags = SA_NOCLDWAIT; //Prevent the child process from becoming a zombie state and avoid the trouble of receiving zombies sigaction(SIGCHLD,&sa,&osa);//Specify a behavior for a signal and put the previous behavior into osa. sa.sa_handler = usr2_handlers; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIG_NOTIFY,&sa,&osa); //Blocking signal sigemptyset(&set);//Clear set into empty set sigaddset(&set,SIG_NOTIFY); //Block set and save other states in oset sigprocmask(SIG_BLOCK,&set,&oset); //Automatically allocate space, read / write, share, anonymous mapping, which is equivalent to malloc serverpool = mmap(NULL,sizeof(struct sever_st)*MAXCLIENTS,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); if (serverpool == MAP_FAILED) { perror("mmap()"); exit(1); } //initialization for (int i = 0; i < MAXCLIENTS; i++) { serverpool[i].pid = -1; } sd = socket(AF_INET,SOCK_STREAM,0/*Streaming socket ipproto is supported by default_ TCP,IPPRORO_ SCTP*/); //socket if (sd<0) { perror("socket()"); exit(1); } /*In order to solve the problem that the used address can be used at any time*/ if(setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))<0) { perror("setsockopt()"); exit(1); } int val = 1; /*In order to solve the problem that the used address can be used at any time*/ if(setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))<0) { perror("setsockopt()"); exit(1); } localaddr.sin_family = AF_INET;//protocol family inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr);//The specified IP address (dotted fraction) is converted into a large integer and stored in localaddr sin_ addr localaddr.sin_port = htons(atoi(SERVERPORT));//port //Bind my port and my IP if (bind(sd,(void*)&localaddr,sizeof(localaddr)) < 0) //connect { perror("bind()"); exit(1); } if(listen(sd,100)<0) //Listening. The second parameter is the size of the full connection queue { perror("listen()"); exit(1); } for (i = 0; i < MINSPARESERVER; i++) { add_1_server(); } while (1) { sigsuspend(&oset);//Signal driver scanf_pool(); //control the pool; if (idle_count > MAXSPARESERVER) { for (i = 0; i < (idle_count - MAXSPARESERVER); i++) del_1_server();//Reduce sever ports one at a time } else if(idle_count<MINSPARESERVER) { for (i = 0; i < (MINSPARESERVER - idle_count); i++) add_1_server();//Add one sever port at a time } //printf the pool for ( i = 0; i < MAXCLIENTS; i++) { if (serverpool[i].pid == -1) { putchar(' '); } else if(serverpool[i].state == STATE_IDEL) { putchar('.'); } else { putchar('x'); } putchar('\n'); } } //Recovery signal sigprocmask(SIG_SETMASK,&oset,NULL); }