/*******************************
服务器端
****************************/
#include <stdio.h>
#include <stdlib.h>#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#define BACKLOG 5
int main(int argc, char** argv){
if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);
int listenfd;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("listen error\n");
}
struct sockaddr_in srvaddr;
bzero(&srvaddr,sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(PORT);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
printf("set sock error");
}
if(bind(listenfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) < 0)
{
printf("bind error\n");
close(listenfd);
exit(1);
}
if(listen(listenfd, BACKLOG) < 0)
{
printf("listen error\n");
}
struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn;
int i;
int client[FD_SETSIZE];
for(i = 0; i < FD_SETSIZE; i++){
client[i] = -1;
}
///
int nready;
int maxfd = listenfd;
fd_set rset;
fd_set aset;
FD_ZERO(&rset);
FD_ZERO(&aset);
FD_SET(listenfd, &aset);
while(1)
{
rset = aset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
/*功能:检查多个文件描述符(socket描述符)是否就绪,当某一个描述符就绪(可读、可写或发生异常)时函数返回,可以实现输入输出多路复用
返回值:有描述符就绪则返回就绪的描述符个数;超时时间内没有描述符就绪返回0;执行失败返回 -1
*/
if (nready == -1)
{
if(errno == EINTR){
continue;
}
printf("select error\n");
}
if (nready == 0)///描述符就绪
{
continue;
}
int conn1;
if(FD_ISSET(listenfd, &rset)) {//如果描述符就绪
peerlen = sizeof(peeraddr);
if((conn = accept(listenfd, (struct sockaddr*) &peeraddr, &peerlen)) < 0)//如果监听端口就绪 来一个用户监听一个用户 并把返回的值给conn
{
printf("accept error");//接收失败
}
FD_SET(conn, &aset);
for(i = 0; i <FD_SETSIZE; i++)//每来一个用户fd_setsize -1
{
if(client[i] < 0)
{
client[i] = conn;
if( i > maxfd)
maxfd = i;
break;
}
}
if(i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("received from client by accept: %s, %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
if(conn > maxfd)
maxfd = conn;
if(--nready <= 0)
continue;
}
char recvbuf[1024];
char sendbuf[1024];
for(i = 0 ; i < maxfd ; i++){
conn = client[i];
conn1 = client[i+1];
/*********************************
文件描述符相当与指针 指向不同客户端
检查文件描述符conn是否可以准备 如果是
从文件描述符conn发送到conn1 实现conn向conn1发送信息
如果不是 看conn1是否就绪 如果是
从文件描述符conn1发送到conn 实现conn1向conn发送信息
*********************************/
if(FD_ISSET(conn, &rset) ){
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn, recvbuf, 1024);
if(ret == -1) {
printf("read error");
break;
}
if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}
fputs(recvbuf, stdout);
write(conn1, recvbuf, strlen(recvbuf));
if(-- nready <=0 )
{
break;
}
}
if(FD_ISSET(conn1, &rset) )
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn1, recvbuf, 1024);
if(ret == -1) {
printf("read error");
break;
}
if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}
fputs(recvbuf, stdout);
write(conn, recvbuf, strlen(recvbuf));
if(-- nready <=0 )
{
break;
}
}
}
}
}
/*********************************
客户端
******************************/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
//这个函数就是用来发送信息到服务器
void echo_cli(int sock)
{
fd_set rset;
FD_ZERO(&rset);
// jiancedao shijian geshu
int nready;
int fd_stdin = fileno(stdin);
int maxfd;
if(fd_stdin > sock)
{
maxfd = fd_stdin;
} else
{
maxfd = sock;
}
char sendbuf[1024]= {0};
char recvbuf[1024]= {0};
while(1){
FD_SET(fd_stdin, &rset);
FD_SET(sock, &rset);
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(nready == -1)
{
printf("select error");
}
if(nready == 0)
{
continue;
}
if(FD_ISSET(sock, &rset)){
int ret = read(sock, recvbuf, sizeof(recvbuf));
if(ret == 0 )
{
printf("server close\n");
break;
}
fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
}
if(FD_ISSET(fd_stdin, &rset)){
if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
break;
write(sock,sendbuf,strlen(sendbuf));
}
}
close(sock);
}
int main(int argc, char** argv){
if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
{
printf("connect error\n");
close(sock);
exit(1);
}
echo_cli(sock);
}