作者: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退出程序!
用户已登录!请重新打开窗口输入!
------------------------
阅读(815) | 评论(0) | 转发(0) |