Chinaunix首页 | 论坛 | 博客
  • 博客访问: 57366
  • 博文数量: 15
  • 博客积分: 50
  • 博客等级: 民兵
  • 技术积分: 55
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-01 09:50
文章分类
文章存档

2014年(1)

2013年(7)

2012年(8)

分类: C/C++

2013-05-07 10:10:49

原文地址:冯伟浩 2012.6.5 C/S-单播 作者:ztguang

作者:2010级嵌入式  冯伟浩

问题由来:  http://blog.chinaunix.net/uid-14735472-id-3216962.html

++++++++++++++++++++++++++++++++++
[root@bogon ~]# gedit
server.c
/* server.c */
#include
#include
#include
#include
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000
char buf[MAXLINE];
int client[FD_SETSIZE];
int i;
int maxi;
int doit(char *var, char *vbr);
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd; int p=0,l=0,k=0,j;
int nready, client[FD_SETSIZE];
ssize_t n;
pthread_t tidA;
fd_set rset, allset;
char buf[MAXLINE];
memset(buf,0,MAXLINE);
char str[INET_ADDRSTRLEN];
socklen_t cliaddr_len;
struct sockaddr_in cliaddr, servaddr;
char dbuf[]="--";
char cbuf[]="已登录!";
char fbuf[]="收到的信息";
char ebuf[]="用户已登录!请重新打开窗口输入!";
char sookset1[MAXLINE][MAXLINE];
memset(sookset1,0,MAXLINE*MAXLINE*sizeof(char));
char buf2[MAXLINE][MAXLINE];
char buf3[MAXLINE][MAXLINE];
memset(buf3,0,MAXLINE*MAXLINE*sizeof(char));
listenfd = Socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);

Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

Listen(listenfd, 20);

maxfd = listenfd;
maxi = -1;
for (i = 0; i client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for (;;) {
rset = allset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);//剔除
if (nready < 0)
perr_exit("select error");

if (FD_ISSET(listenfd, &rset)) {
cliaddr_len = sizeof(cliaddr);
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));

for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
printf("i=%d\n",i);
//打印I的值,i从0开始加
client[i] = connfd; /* save descriptor */
sookset1[i][0]=connfd;
//定义二维数组只用下标为[i][0]的位置来存放文件描述符!每打开一个客户端链接i的值自动的加加。。i从0开始加..存放客户端文件描述符的分别是[0][0],[1][0],[2][0]
printf("sookset1[p][0]=%s\n",sookset1[p]);
//控制流程将sookset1[p]的值打印出来。
break;
}

if (i == FD_SETSIZE) {
fputs("too many clients\n", stderr);
exit(1);
}

FD_SET(connfd, &allset);
if (connfd > maxfd)
maxfd = connfd;
if (i > maxi)
maxi = i;
if (--nready == 0)
continue;
}

for (i = 0; i <= maxi; i++) {
if ( client[i] < 0)
{continue;}else
{
sockfd = client[i];
}
lable1: if (FD_ISSET(sockfd, &rset)) {
memset(buf,0,MAXLINE);
if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
} else {
printf("maxi=%d\n",maxi);
for(j = 0; j <= maxi; j++)
{
printf("buf3[1]=%s\n",buf3[j]);
printf("buf=%s\n",buf);
if(strcmp(buf3[j],buf)==0)
{
for (i = 0; i <= maxi; i++)
{
Write(client[i], ebuf, n);
} goto lable1;
}
}
if(strstr(buf,dbuf)==NULL)
//用来判断客户端输入的是用户名还是信息!查找buf中是否含有dbuf,我觉的这个用的不好,但是一时也没想开咋该。
{
printf("执行了一次!\n"); //成功执行这下面的代码,控制流程
printf("i=%d\n",i); //打印活动的文件描述符的下标!从0开始
strcat(sookset1[i],buf);//将文件描述符和用户输入的用户名进行链接,分别放入sookset1中
printf("sookset1[i]=%s\n",sookset1[i]); //打印链接后的sookset1[i]
strcat(buf2[i],buf);
strcat(buf3[i],buf);
printf("buf2[i]=%s\n",buf2[i]);
strcat(buf2[i],dbuf);//必须是英文情况下的--
strcat(buf2[i],cbuf);//执行后即为谁--已登录
//strcat(buf2[i],buf);
for (i = 0; i <= maxi; i++)
for (j = 0; j<= maxi; j++)
{
Write(client[i], buf2[j], n);//每次客户运行将已登录的信息循环发给每个用户
}//将客户端输入的信息循环写入
}else{ //如果输入的是信息执行下列代码
for(j=0;j<=maxi;j++)
{
printf("打印@\n");
printf("buf=%s\n",buf);//将读入的客户端信息放入buf中并打印
printf("sookset1[j]=%s\n",sookset1[j]); //将此时sookset1[j]的信息打印出来
if(doit(sookset1[j],buf)==1)//判断sookset1[j]的信息何buf的信息是否相等
{
printf("sookset1[j][0]=%c\n",sookset1[j][0]); //打印此时的文件描述符
j=(int)sookset1[j][0];//将sookset1[j][0]中的文件描述符转化为整形
printf("%d\n",j);
Write(j, buf, n);//将信息写入客户端
}
}
}

}
if (--nready == 0)
break;
}
}
}
}

int doit(char *var, char *vbr) //函数用来比较sookset1[j]和buf是否相等,此时sookset1[j]相当于一维字符串数组
{
int k;
for(k=0;k<10;k++)
{
if(var[k+1]=='-' || vbr[k]=='-')
//for循环下标从头开始比较,因为sookset1[j]中sookset1[j][0]为文件描述符所以从k+1处开始比较
{
break;
}else{
if(var[k+1]==vbr[k])
{
continue;
}else{
if(var[k+1]!=vbr[k])
{
return 0;
}
}
}
}
return 1;

}

++++++++++++++++++++++++++++++++++++
[root@bogon ~]# gedit client.c
/* client.c */
#include
#include
#include
#include
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000
void *doit(void *arg);
char buf[MAXLINE];
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
memset(buf,0,MAXLINE);
int sockfd, n;
pthread_t tidA;
if (argc != 2) {
fprintf(stderr,"请输入要发送的信息\n");
exit(1);
}
strcpy(buf,argv[1]);

sockfd = Socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
printf("请输入用户名形如xxx--xxx\n");
printf("请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!\n");
printf("如果输入重复的用户名!请重新打开窗口!\n");

printf("请输入esc退出程序!\n");
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
write(sockfd,buf,MAXLINE);
while (1) {
pid_t pid;
char *message;
int n;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid == 0) {
memset(buf,0,MAXLINE);
n = Read(sockfd, buf, MAXLINE);
if (n == 0)
{ printf("the servre has closed.\n");break; }
else
//Write(STDOUT_FILENO, buf, n);
printf("%s\n",buf);
printf("------------------------\n");
} else {
fgets(buf, MAXLINE, stdin);
if(memcmp(buf,"esc",3)==0)
{
exit(1);
}
Write(sockfd, buf, strlen(buf));
}

}

Close(sockfd);
return 0;
}

++++++++++++++++++++++++++++++++++++++++
[root@bogon ~]# gedit wrap.h

#include
#include
#include

void perr_exit(const char *s)
{
        perror(s);
        exit(1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
        int n;

      again:
        if ((n = accept(fd, sa, salenptr)) < 0) {
                if ((errno == ECONNABORTED) || (errno == EINTR))
                        goto again;
                else
                        perr_exit("accept error");
        }
        return n;
}

void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
        if (bind(fd, sa, salen) < 0)
                perr_exit("bind error");
}

void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
        if (connect(fd, sa, salen) < 0)
                perr_exit("connect error");
}

void Listen(int fd, int backlog)
{
        if (listen(fd, backlog) < 0)
                perr_exit("listen error");
}

int Socket(int family, int type, int protocol)
{
        int n;

        if ((n = socket(family, type, protocol)) < 0)
                perr_exit("socket error");
        return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
        ssize_t n;

      again:
        if ((n = read(fd, ptr, nbytes)) == -1) {
                if (errno == EINTR)
                        goto again;
                else
                        return -1;
        }
        return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
        ssize_t n;

      again:
        if ((n = write(fd, ptr, nbytes)) == -1) {
                if (errno == EINTR)
                        goto again;
                else
                        return -1;
        }
        return n;
}

void Close(int fd)
{
        if (close(fd) == -1)
                perr_exit("close error");
}

ssize_t Readn(int fd, void *vptr, size_t n)
{
        size_t nleft;
        ssize_t nread;
        char *ptr;

        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
                if ((nread = read(fd, ptr, nleft)) < 0) {
                        if (errno == EINTR)
                                nread = 0;
                        else
                                return -1;
                } else if (nread == 0)
                        break;

                nleft -= nread;
                ptr += nread;
        }
        return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;

        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
                if ((nwritten = write(fd, ptr, nleft)) <= 0) {
                        if (nwritten < 0 && errno == EINTR)
                                nwritten = 0;
                        else
                                return -1;
                }

                nleft -= nwritten;
                ptr += nwritten;
        }
        return n;
}

static ssize_t my_read(int fd, char *ptr)
{
        static int read_cnt;
        static char *read_ptr;
        static char read_buf[100];

        if (read_cnt <= 0) {
              again:
                if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                        if (errno == EINTR)
                                goto again;
                        return -1;
                } else if (read_cnt == 0)
                        return 0;
                read_ptr = read_buf;
        }
        read_cnt--;
        *ptr = *read_ptr++;
        return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
        ssize_t n, rc;
        char c, *ptr;

        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
                if ((rc = my_read(fd, &c)) == 1) {
                        *ptr++ = c;
                        if (c == '\n')
                                break;
                } else if (rc == 0) {
                        *ptr = 0;
                        return n - 1;
                } else
                        return -1;
        }
        *ptr = 0;
        return n;
}

+++++++++++++++++++++++++++++
执行过程:
客户端一:[root@bogon  select]# ./clie3 asd
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
asd--已登录!
------------------------
asd--已登录!
------------------------
qwe--已登录!
------------------------
asd--asdfsdfsdf    //qwe给asd的信息

------------------------
qwe--asdfsdfdsf   //发给qwe的信息
asd--已登录!
------------------------
qwe--已登录!
------------------------
zxc--已登录!
------------------------
asd--sadfdsf   //zxc给asd的信息

------------------------
zxc--asdfdsf    //回给zxc的信息
用户已登录!请重新打开窗口输入!   //  //将第四个重复的用户也广播出去!
客户端二:
[root@bogon  select]# ./clie3 qwe
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
asd--已登录!
------------------------
qwe--已登录!
------------------------
asd--asdfsdfsdf     发给asd的信息
qwe--asdfsdfdsf    asd 发给qwe的信息

------------------------
asd--已登录!
------------------------
qwe--已登录!
------------------------
zxc--已登录!
------------------------
用户已登录!请重新打开窗口输入!           //将第四个重复的用户也广播出去!
------------------------
客户端三:
[root@bogon  select]# ./clie3 zxc
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
asd--已登录!
------------------------
qwe--已登录!
------------------------
zxc--已登录!
------------------------
asd--sadfdsf    
zxc--asdfdsf

------------------------
用户已登录!请重新打开窗口输入!    //  //将第四个重复的用户也广播出去!
------------------------
[root@bogon  select]# ./clie3 asd              //登录用户名重复!
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
用户已登录!请重新打开窗口输入!
------------------------




阅读(1713) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~