//client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
\
}while(0)
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nread = read(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nread == 0) //若对方已关闭
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nwritten = write(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nwritten == 0)
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
}
ssize_t recv_peek(int sockfd, void *buf, ssize_t len)
{
while (1)
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == -1 && errno == EINTR)
{
continue;
}
return ret;
}
}
ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while (1)
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < 0)
return ret;
else if (ret == 0)
return ret;
nread = ret;
int i;
for (i = 0; i < nread; ++i)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i + 1);
if ( ret != (i + 1))
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -1;
}
void echo_cli (int conn)
{
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{
writen(conn, sendbuf, strlen(sendbuf));
//read(conn, recvbuf, 1024);
int ret = readline(conn, recvbuf, 1024);
if (ret == -1)
ERR_EXIT("readline failed\n");
if (ret == 0)
{
printf("server close\n");
break;
}
fputs(recvbuf, stdout);
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
}
}
int main()
{
int sockfd;
//建立socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("create socket failed");
return 1;
}
//connect 连接server
struct sockaddr_in serveraddr_in;
memset(&serveraddr_in, 0, sizeof(serveraddr_in));
serveraddr_in.sin_family = AF_INET;
serveraddr_in.sin_port = htons(12345); /* port in network byte order */
serveraddr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
if ( connect(sockfd, (struct sockaddr *)&serveraddr_in, sizeof(serveraddr_in) ) == -1)
{
perror("connect failed");
return 1;
}
struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if (getsockname(sockfd, (struct sockaddr*)&localaddr, &addrlen) < 0)
{
ERR_EXIT("getsockname failed\n");
}
printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));
echo_cli(sockfd);
return 0;
}
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
\
}while(0)
/*
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
struct in_addr {
uint32_t s_addr;
};
*/
/*
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
*/
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nread = read(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nread == 0) //若对方已关闭
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nwritten = write(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nwritten == 0)
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
}
ssize_t recv_peek(int sockfd, void *buf, ssize_t len)
{
while (1)
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == -1 && errno == EINTR)
continue;
return ret;
}
}
ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while (1)
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < 0)
return ret;
else if (ret == 0)
return ret;
nread = ret;
int i;
for (i = 0; i < nread; ++i)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i + 1);
if ( ret != (i + 1))
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -1;
}
void echo_srv (int conn)
{
char recvbuf[1024];
while (1)
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn, recvbuf, 1024);/*test*/
//int ret = readline(conn, recvbuf, 1024);
if (ret == -1)
{
ERR_EXIT("readline failed");
break;
}
if (ret == 0)
{
printf("client close\n");
break;
}
fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf));
}
kill(getppid(),SIGCHLD);
}
void handle_sigchld(int sig)
{
int mypid = 0;
while ( (mypid = waitpid(-1, NULL, WNOHANG) ) > 0)
{
;
}
}
int main()
{
//避免Zombie process的方法一,发送不可靠信号:
//signal(SIGCHLD, SIG_IGN);
//避免Zombie process的方法二,推荐使用:
signal(SIGCHLD, handle_sigchld);
int serverfd;
//建立socket
serverfd = socket(AF_INET, SOCK_STREAM, 0);
if (serverfd == -1)
{
perror("create socket failed");
return 1;
}
//给TCP设置地址可重用
int on = 1;
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
printf("setsockopt failed %s\n", strerror(errno));
return EXIT_FAILURE;
}
//bind 绑定端口,IP
struct sockaddr_in serveraddr_in;
memset(&serveraddr_in, 0, sizeof(serveraddr_in));
serveraddr_in.sin_family = AF_INET;
serveraddr_in.sin_port = htons(12345); /* port in network byte order */
serveraddr_in.sin_addr.s_addr = inet_addr("0.0.0.0");
if ( bind(serverfd, (struct sockaddr *)&serveraddr_in, sizeof(serveraddr_in)) == -1)
{
perror("bind failed");
return 1;
}
//listen 被动套接字,监听端口
if (listen(serverfd, 20) == -1)
{
perror("listen failed");
return 1;
}
while (1)
{
//accept 阻塞等待client连接
int clientfd = -1;
struct sockaddr_in clientaddr_in;
memset(&clientaddr_in, 0, sizeof(clientaddr_in));
socklen_t clientaddr_len = sizeof(clientaddr_in);
if ( (clientfd = accept(serverfd, (struct sockaddr *)&clientaddr_in, &clientaddr_len) ) == -1)
{
perror("accept failed");
return 1;
}
else
{
printf("\n\nclient %s:%d connected\n\n", inet_ntoa(clientaddr_in.sin_addr), ntohs(clientaddr_in.sin_port));
}
int pid =fork();
if( pid == -1 )
{
ERR_EXIT("fork failed");
}
else if (pid == 0)
{
//子进程关闭被动套接字
close(serverfd);
echo_srv(clientfd);
return EXIT_FAILURE;
}
else
{
//主进程关闭一个主动套接字clientfd
close(clientfd);
}
}
//close 正常关闭
close(serverfd);
return 0;
}
备份地址: 【Socket PRGM: chat_1Vn】