客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/select.h>
#include <netdb.h>
#define BUFSIZE 4096
int connect_nblock(int sockfd,struct sockaddr* to,socklen_t tolen) {
int val;
if ((val = fcntl(sockfd,F_GETFL,0)) < 0) {
fprintf(stderr,"fcntl error: %s\n",strerror(errno));
exit(1);
}
if (fcntl(sockfd,F_SETFL,val | O_NONBLOCK) < 0) {
fprintf(stderr,"fcntl error: %s\n",strerror(errno));
exit(1);
}
int n;
if ((n = connect(sockfd,to,tolen)) < 0) {
if (errno != EINPROGRESS) {
return -1;
}
}
if (n == 0) {
if (fcntl(sockfd,F_SETFL,val) < 0) {
fprintf(stderr,"fcntl error: %s\n",strerror(errno));
exit(1);
}
return 0;
}
fd_set ws,rs;
FD_ZERO(&ws);
FD_ZERO(&rs);
FD_SET(sockfd,&ws);
FD_SET(sockfd,&rs);
struct timeval tv;
tv.tv_sec = 40;
tv.tv_usec = 0;
if (select(sockfd + 1,&rs,&ws,NULL,&tv) == 0) {
return -1;
}
if (FD_ISSET(sockfd,&ws) || FD_ISSET(sockfd,&rs)) {
struct sockaddr_storage peer;
socklen_t len = sizeof(struct sockaddr_storage);
if (getpeername(sockfd,(struct sockaddr*)&peer,&len) == ENOTCONN) {
return -1;
}else {
if (fcntl(sockfd,F_SETFL,val) < 0) {
fprintf(stderr,"fcntl error: %s\n",strerror(errno));
exit(1);
}
return 0;
}
}else {
return -1;
}
}
void client_echo(int sockfd) {
char send[BUFSIZE];
int n;
while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) {
if (write(sockfd,send,n) != n) {
printf("write to socket error: %s\n",strerror(errno));
exit(1);
}
if ((n = read(sockfd,send,n)) < 0) {
printf("read on socket error: %s\n",strerror(errno));
exit(1);
}
if (write(STDOUT_FILENO,send,n) != n) {
printf("write to stdout error: %s\n",strerror(errno));
exit(1);
}
}
}
int main(int argc,char** argv) {
if (argc != 3) {
printf("please check or add <ip address or host name> or <service name or port>\n");
exit(1);
}
struct addrinfo hints;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_ALL;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* results;
int err;
if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) {
printf("getaddrinfo error: %s\n",gai_strerror(err));
exit(1);
}
struct addrinfo* dummy = results;
int sockfd;
for (; dummy != NULL; dummy = dummy->ai_next) {
if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
continue;
}
if (connect_nblock(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
break;
}
close(sockfd);
}
if (dummy == NULL) {
printf("all socket failed\n");
freeaddrinfo(results);
exit(1);
}
freeaddrinfo(results);
client_echo(sockfd);
return 0;
}
服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/wait.h>
#define BUFSIZE 4096
#define LISTENQ 100
void sig_child(int signo) {
int ppid;
while ((ppid = waitpid(-1,NULL,WNOHANG)) > 0) {
printf("child process: %d terminated\n",ppid);
}
}
void server_echo(int fd) {
char recv[BUFSIZE];
int n;
struct msghdr rvmsg;
struct iovec io;
struct sockaddr_storage from;
struct cmsghdr control;
io.iov_base = recv;
io.iov_len = BUFSIZE;
rvmsg.msg_name = &from;
rvmsg.msg_iov = &io;
rvmsg.msg_iovlen = 1;
rvmsg.msg_control = &control;
rvmsg.msg_controllen = sizeof(struct cmsghdr);
struct msghdr sdmsg;
while ((n = recvmsg(fd,&rvmsg,0)) > 0) {
sdmsg.msg_name = rvmsg.msg_name;
sdmsg.msg_namelen = rvmsg.msg_namelen;
sdmsg.msg_iov = &io;
sdmsg.msg_iovlen = 1;
sdmsg.msg_control = NULL;
sdmsg.msg_controllen = 0;
sdmsg.msg_flags = 0;
io.iov_len = n;
if (sendmsg(fd,&sdmsg,0) != n) {
printf("send message to client failed: %s\n",strerror(errno));
exit(1);
}
io.iov_len = BUFSIZE;
}
}
int main(int argc,char** argv) {
if (argc != 2) {
printf("please check <service name or port>\n");
exit(1);
}
struct addrinfo hints;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* results;
int err;
if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) {
printf("getaddrinfo error: %s\n",gai_strerror(err));
exit(1);
}
struct addrinfo* dummy = results;
int sockfd;
for (; dummy != NULL; dummy = dummy->ai_next) {
if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
continue;
}
if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
break;
}
close(sockfd);
}
if (dummy == NULL) {
freeaddrinfo(results);
printf("all failed\n");
exit(1);
}
freeaddrinfo(results);
if (listen(sockfd,LISTENQ) < 0) {
printf("listen error: %s\n",strerror(errno));
exit(1);
}
int connfd;
int pid;
if (signal(SIGCHLD,sig_child) == SIG_ERR) {
printf("signal error: %s\n",strerror(errno));
exit(1);
}
for (; ;) {
if ((connfd = accept(sockfd,NULL,NULL)) < 0) {
if (errno == EINTR) {
continue;
}else {
printf("accept error: %s\n",strerror(errno));
exit(1);
}
}
if ((pid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (pid == 0) {
close(sockfd);
server_echo(connfd);
close(connfd);
exit(0);
}
close(connfd);
}
return 0;
}