注意:readset被每次需要重新set,所以用allset先保存下来,每次重新赋值给readset
server.c
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*
int socket(int domain, int type, int protocol);
*/
/*
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
//man 2 bind
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
//man 7 ip
struct sockaddr_in {
sa_family_t sin_family; // address family: AF_INET
u_int16_t sin_port; // port in network byte order
struct in_addr sin_addr; // internet address
};
//Internet address.
struct in_addr {
u_int32_t s_addr; //address in network byte order
};
*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*
On success, accept() returns a non-negative integer that is a descriptor for the accepted socket.
On error, -1 is returned, and errno is set appropriately.
*/
int main()
{
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("fun socket");
exit(0);
}
struct sockaddr_in srvaddr;
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8001);
srvaddr.sin_addr.s_addr = (INADDR_ANY);
int on = 1;
//bind socket error: Address already in use
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
perror("setsockopt");
return -1;
}
if (bind(sockfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) < 0)
{
perror("fun bind");
return -1;
}
if (listen(sockfd, SOMAXCONN) < 0)
{
perror("fun listen");
return -1;
}
int i;
int client[FD_SETSIZE];
int maxi = 0;
memset(client,-1,FD_SETSIZE);
fd_set read_set;
fd_set all_set;
FD_ZERO(&read_set);
FD_ZERO(&all_set);
int maxfd = sockfd;
FD_SET(sockfd,&all_set);
while(1)
{
read_set = all_set;//重新准备要被监听的文件描述符集合,这也是select的缺点之一
int nready = select(maxfd+1,&read_set,NULL,NULL,NULL);
if(nready == -1)
{
if(errno == EINTR)
continue;
return -1;
}
else if(nready == 0)
{
continue;//timeout
}
if(FD_ISSET(sockfd,&read_set))
{
struct sockaddr_in peer_addr;
//The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr;
socklen_t peerlen = sizeof(peer_addr);
int conn = accept(sockfd,(struct sockaddr*)&peer_addr,&peerlen);
if(conn == -1)
{
perror("accept error");
return -1;
}
printf("perradd:%s\n perrport:%d\n", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
for(i = 0; i < FD_SETSIZE; i++)
{
if(client[i] == -1)
{
client[i] = conn;
if(i > maxi)
maxi = i;
break;
}
}
FD_SET(conn,&all_set);
if(conn > maxfd)
maxfd = conn;
if(--nready > 0)
continue;
}
for(i = 0; i <= maxi; i++)
{
int conn = client[i];
if(conn == -1)
continue;
if(FD_ISSET(conn,&read_set))
{
char recvbuf[1204];
memset(recvbuf,0x00,sizeof(recvbuf));
int nread = read(conn,recvbuf,sizeof(recvbuf));
if(nread == 0)
{
printf("peer has closed\n");
FD_CLR(conn,&all_set);
client[i] = -1;
close(conn);
}
fputs(recvbuf,stdout);
write(conn,recvbuf,nread);
memset(recvbuf,0x00,sizeof(recvbuf));
}
}
}
return 0;
}
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
/*
int socket(int domain, int type, int protocol);
*/
/*
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
//man 2 bind
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
//man 7 ip
struct sockaddr_in {
sa_family_t sin_family; // address family: AF_INET
u_int16_t sin_port; // port in network byte order
struct in_addr sin_addr; // internet address
};
//Internet address.
struct in_addr {
u_int32_t s_addr; //address in network byte order
};
*/
//int listen(int sockfd, int backlog);
//accept 接受一个新的连接 ,这个新的连接是一个主动套接字
/* int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
On success, accept() returns a non-negative integer that is a descriptor for the accepted socket. On error,
-1 is returned, and errno is set appropriately.
int conn = 0;
*/
int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("./client IPAddress\n");
return -1;
}
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("fun socket\n");
exit(0);
}
struct sockaddr_in srvaddr;
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8001);
srvaddr.sin_addr.s_addr = inet_addr(argv[1]); //127.0.0.1
if (connect(sockfd, (struct sockaddr*) (&srvaddr), sizeof(srvaddr)) < 0) {
perror("fun socket\n");
exit(0);
}
printf("connect success\n");
char revbuf[1024] = { 0 };
char sendbuf[1024] = { 0 };
/*
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) {
//向服务写数据
write(sockfd, sendbuf, strlen(sendbuf));
//从服务器读数据
read(sockfd, revbuf, sizeof(revbuf));
//
fputs(revbuf, stdout); //从服务器收到数据,打印屏幕
memset(revbuf, 0, sizeof(revbuf));
memset(sendbuf, 0, sizeof(sendbuf));
}
*/
fd_set read_set;
FD_ZERO(&read_set);
int stdin_fd = fileno(stdin);
int maxfd = (sockfd > stdin_fd ? sockfd : stdin_fd);
fd_set all_set;
FD_ZERO(&all_set);
FD_SET(stdin_fd,&all_set);
FD_SET(sockfd,&all_set);
while(1)
{
read_set = all_set;
int ret = select(maxfd+1,&read_set,NULL,NULL,NULL);
if(ret == -1)
{
perror("select error");
return -1;
}
else if(ret == 0)
{
printf("timeout\n");
return -1;
}
else if(ret == 1)
{
if(FD_ISSET(stdin_fd,&read_set))
{
fgets(sendbuf,sizeof(sendbuf),stdin);
write(sockfd, sendbuf, strlen(sendbuf));
memset(sendbuf, 0, sizeof(sendbuf));
printf("write sock\n");
}
if(FD_ISSET(sockfd,&read_set))
{
int nread = read(sockfd, revbuf, sizeof(revbuf));
if(nread == 0)
{
printf("peer closed\n");
break;
}
fputs(revbuf, stdout);
memset(revbuf, 0, sizeof(revbuf));
printf("read sock\n");
}
}
}
close(sockfd);
return 0;
}