吴晓培 2012.6.21 C/S-单播-线程
来源:互联网 发布:国内编程语言排行2016 编辑:程序博客网 时间:2024/05/16 13:03
作者:2010级嵌入式 吴晓培
问题由来: http://blog.chinaunix.net/uid-14735472-id-3216962.html
[root@bogon ~]# gedit server.c/* 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];//nready存放有数据请求的客户端的个数;FD_SETSIZE是tcp最大连接数,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);//socket()打开一个网络通讯端口,返回一个套接字描述符给listenfd;
bzero(&servaddr, sizeof(servaddr));//首先将结构体清零;
servaddr.sin_family = AF_INET; //设置地址类型为AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//转换ip地址字节序,网络地址为INADDR_ANY,这个宏表示本地任意IP地址
servaddr.sin_port = htons(SERV_PORT);//转换端口的字节序。到目前为止,结构体servaddr的设置已经完毕;
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //将所监听的端口号与服务器的地址、端口绑定;
Listen(listenfd, 20);//listen()声明服务器处于监听状态,并且最多允许有20个客户端处于连接待状态;
maxfd = listenfd;//将所监听的最大的套接字描述符赋给maxfd;
maxi = -1;
for (i = 0; i client[i] = -1;
FD_ZERO(&allset); //将allset套接字描述符集清空。
FD_SET(listenfd, &allset);//向allset套接字描述符集中添加服务器所监听到的端口(即listenfd所接受到的请求);
for (;;) {
rset = allset;// 把allset套接字描述符集的内容赋给rset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);//select用于监听多个阻塞的文件描述符,当这些被阻塞的端口有数据请求或要与服务器交互时,select就会返回请求客户端的个数给nready,若没有,则返回0,若select调用出错,则会返回一个负值。由于最后一个关于时间的参数值是null,所以select会一直阻塞等待着client的请求,直到有数据交互的客户端产生。maxfd+1表示集合中描述符的范围即所有描述符的最大值加1,rset则是在关注哪个客户端有数据可读了,就把客户端的套接字描述符添加在rset集合中。
if (nready < 0)
perr_exit("select error");//select调用出错时,会返回一个负数给nready。该语句判断select是否调用成功。
if (FD_ISSET(listenfd, &rset))
//判断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++)//for循环,i作为client的下标,表示放有数据请求的客户端的最小索引
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)//若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
continue;//继续执行for循环,查找数据请求的客户端
}
for (i = 0; i <= maxi; i++) {
if ( client[i] < 0)//把client[i]中存放的客户端的套接字描述符赋给sockfd。若小于0,表示这个client[i]中没有放置套接字描述符。
{continue;}else
{
sockfd = client[i];
}
lable1: if (FD_ISSET(sockfd, &rset)) {
memset(buf,0,MAXLINE);//初始化buf数组
if ((n = Read(sockfd, buf, MAXLINE)) == 0)
// 读入客户端的数据,若n等于0表示客户端已经关闭了连接;
{
Close(sockfd);//客户端关闭连接了,服务器也关闭与客户端相应的连接;
FD_CLR(sockfd, &allset);
client[i] = -1;//同时将放置这个客户端套接字的数组位置设为-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) //比较看buf存放的客户登录信息是否在buf[3]客户登录信息集中存在!
{
for (i = 0; i <= maxi; i++) //如果存在则把ebuf中的信息循环打印给每一个登录的客户!
{
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]) //判断var和vbr下标为k+1和k的元素的只是否相同!如果相同则进行下一次比较!
{
continue;
}else{
if(var[k+1]!=vbr[k])//如果var和vbr下标为k+1和k的元素不相同则退处函数返回0
{
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);
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]); //将argv[1]里的数据复制到buf中!buf用于存放客户端与服务器端交互时的数据;
sockfd = Socket(AF_INET, SOCK_STREAM, 0); //socket()打开一个网络通讯端口,返回一个套接字描述符给sockfd;
bzero(&servaddr, sizeof(servaddr));//首先将servaddr结构体清零;
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//与服务器建立链接;
printf("请输入用户名形如xxx--xxx\n");
printf("请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!\n");
printf("如果输入重复的用户名!请重新打开窗口!\n");
printf("请输入esc退出程序!\n");
printf("当前登录用户是%s\n",buf);
write(sockfd,buf,MAXLINE); //把buf里的信息写到sockfd文件描述符里
memset(buf,0,MAXLINE);
while(1)
{
pthread_create(&tidA, NULL, &doit,&sockfd); //创建线程函数用来和服务器进行发送信息。
}
sleep(3); //主线程睡3秒
return 0;
}
void *doit(void *arg) //线程函数
{
int conut;
int n;
conut = *((int*)arg); //将socked套接字赋值给conut;
char buf[MAXLINE];
memset(buf,0,MAXLINE);
while(1)
{
memset(buf,0,MAXLINE); //每次读之前初始化数组
n = Read(conut, buf, MAXLINE); //将count的数据读到buf中
if (n == 0) //若n等于0表示服务器已经关闭了连接;
{
printf("the servre has closed.\n");
exit(1); //客户端退出程序
}else
{
printf("%s\n",buf);
printf("------------------------\n");
fgets(buf, MAXLINE, stdin); //用fgets从键盘读数据到buf中;
if(memcmp(buf,"esc",3)==0) //如果客户端输入的为esc则客户端退出程序
{
exit(1);
}
Write(conut, buf, strlen(buf)); //把buf中的数据写到socked文件描述符对应的共享区域!
}
}
}
[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@localhost 单播]# ./clie wxp //客户端一
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
当前登录用户是wxp
wxp--已登录!
------------------------
wxp--已登录!
------------------------
zls--已登录!
------------------------
zls--老师您好
[root@localhost 单播]# ./clie zls //客户端二
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
当前登录用户是zls
wxp--已登录!
------------------------
zls--已登录!
------------------------
zls--老师您好!
------------------------
问题由来: http://blog.chinaunix.net/uid-14735472-id-3216962.html
[root@bogon ~]# gedit server.c/* 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];//nready存放有数据请求的客户端的个数;FD_SETSIZE是tcp最大连接数,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);//socket()打开一个网络通讯端口,返回一个套接字描述符给listenfd;
bzero(&servaddr, sizeof(servaddr));//首先将结构体清零;
servaddr.sin_family = AF_INET; //设置地址类型为AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//转换ip地址字节序,网络地址为INADDR_ANY,这个宏表示本地任意IP地址
servaddr.sin_port = htons(SERV_PORT);//转换端口的字节序。到目前为止,结构体servaddr的设置已经完毕;
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //将所监听的端口号与服务器的地址、端口绑定;
Listen(listenfd, 20);//listen()声明服务器处于监听状态,并且最多允许有20个客户端处于连接待状态;
maxfd = listenfd;//将所监听的最大的套接字描述符赋给maxfd;
maxi = -1;
for (i = 0; i
FD_ZERO(&allset); //将allset套接字描述符集清空。
FD_SET(listenfd, &allset);//向allset套接字描述符集中添加服务器所监听到的端口(即listenfd所接受到的请求);
for (;;) {
rset = allset;// 把allset套接字描述符集的内容赋给rset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);//select用于监听多个阻塞的文件描述符,当这些被阻塞的端口有数据请求或要与服务器交互时,select就会返回请求客户端的个数给nready,若没有,则返回0,若select调用出错,则会返回一个负值。由于最后一个关于时间的参数值是null,所以select会一直阻塞等待着client的请求,直到有数据交互的客户端产生。maxfd+1表示集合中描述符的范围即所有描述符的最大值加1,rset则是在关注哪个客户端有数据可读了,就把客户端的套接字描述符添加在rset集合中。
if (nready < 0)
perr_exit("select error");//select调用出错时,会返回一个负数给nready。该语句判断select是否调用成功。
if (FD_ISSET(listenfd, &rset))
//判断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++)//for循环,i作为client的下标,表示放有数据请求的客户端的最小索引
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)//若--nready为0,则表示当前的套接字描述符集中只有listenfd这个监听的描述符,没有客户端的数据请求端口,则进行下一轮的select循环;
continue;//继续执行for循环,查找数据请求的客户端
}
for (i = 0; i <= maxi; i++) {
if ( client[i] < 0)//把client[i]中存放的客户端的套接字描述符赋给sockfd。若小于0,表示这个client[i]中没有放置套接字描述符。
{continue;}else
{
sockfd = client[i];
}
lable1: if (FD_ISSET(sockfd, &rset)) {
memset(buf,0,MAXLINE);//初始化buf数组
if ((n = Read(sockfd, buf, MAXLINE)) == 0)
// 读入客户端的数据,若n等于0表示客户端已经关闭了连接;
{
Close(sockfd);//客户端关闭连接了,服务器也关闭与客户端相应的连接;
FD_CLR(sockfd, &allset);
client[i] = -1;//同时将放置这个客户端套接字的数组位置设为-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) //比较看buf存放的客户登录信息是否在buf[3]客户登录信息集中存在!
{
for (i = 0; i <= maxi; i++) //如果存在则把ebuf中的信息循环打印给每一个登录的客户!
{
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]) //判断var和vbr下标为k+1和k的元素的只是否相同!如果相同则进行下一次比较!
{
continue;
}else{
if(var[k+1]!=vbr[k])//如果var和vbr下标为k+1和k的元素不相同则退处函数返回0
{
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);
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]); //将argv[1]里的数据复制到buf中!buf用于存放客户端与服务器端交互时的数据;
sockfd = Socket(AF_INET, SOCK_STREAM, 0); //socket()打开一个网络通讯端口,返回一个套接字描述符给sockfd;
bzero(&servaddr, sizeof(servaddr));//首先将servaddr结构体清零;
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//与服务器建立链接;
printf("请输入用户名形如xxx--xxx\n");
printf("请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!\n");
printf("如果输入重复的用户名!请重新打开窗口!\n");
printf("请输入esc退出程序!\n");
printf("当前登录用户是%s\n",buf);
write(sockfd,buf,MAXLINE); //把buf里的信息写到sockfd文件描述符里
memset(buf,0,MAXLINE);
while(1)
{
pthread_create(&tidA, NULL, &doit,&sockfd); //创建线程函数用来和服务器进行发送信息。
}
sleep(3); //主线程睡3秒
return 0;
}
void *doit(void *arg) //线程函数
{
int conut;
int n;
conut = *((int*)arg); //将socked套接字赋值给conut;
char buf[MAXLINE];
memset(buf,0,MAXLINE);
while(1)
{
memset(buf,0,MAXLINE); //每次读之前初始化数组
n = Read(conut, buf, MAXLINE); //将count的数据读到buf中
if (n == 0) //若n等于0表示服务器已经关闭了连接;
{
printf("the servre has closed.\n");
exit(1); //客户端退出程序
}else
{
printf("%s\n",buf);
printf("------------------------\n");
fgets(buf, MAXLINE, stdin); //用fgets从键盘读数据到buf中;
if(memcmp(buf,"esc",3)==0) //如果客户端输入的为esc则客户端退出程序
{
exit(1);
}
Write(conut, buf, strlen(buf)); //把buf中的数据写到socked文件描述符对应的共享区域!
}
}
}
[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@localhost 单播]# ./clie wxp //客户端一
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
当前登录用户是wxp
wxp--已登录!
------------------------
wxp--已登录!
------------------------
zls--已登录!
------------------------
zls--老师您好
[root@localhost 单播]# ./clie zls //客户端二
请输入用户名形如xxx--xxx
请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
如果输入重复的用户名!请重新打开窗口!
请输入esc退出程序!
当前登录用户是zls
wxp--已登录!
------------------------
zls--已登录!
------------------------
zls--老师您好!
------------------------
0
上一篇:我的25年嵌入式生涯-周立功
下一篇:Nvidia回应Linux之父的指责 坚持不做任何让步
相关热门文章
- test123
- 编写安全代码——小心有符号数...
- 使用openssl api进行加密解密...
- 一段自己打印自己的c程序...
- sql relay的c++接口
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 吴晓培 2012.6.21 C/S-单播-线程
- 冯伟浩 2012.6.5 C/S-单播
- python单线程文件传输范例(C/S)
- python , 一个简单的单线程的C/S模型示例
- 单播,多播
- 单播&&多播
- 单播
- 107-使用多播的 UDP C/S 程序
- 单播,广播,组播
- 单播、广播、组播
- 单播,广播,组播
- 单播/组播/广播
- 广播 组播 单播
- 组播 广播 单播
- 单播、广播、组播
- 单播,广播,组播
- 单播、广播、组播
- 单播和多播
- 我的25年嵌入式生涯-周立功
- 在Ubuntu中,使用minicom抓串口log
- 动态加载:ViewPager数量
- 分页查询(一)——真假分页学习
- 安卓Service的开启方式
- 吴晓培 2012.6.21 C/S-单播-线程
- Quartz2D 简单介绍及应用(图片裁剪)
- 利用Oracle SQL Developer创建database link数据库连接
- Nvidia回应Linux之父的指责 坚持不做任何让步
- python 使用微信远程控制电脑
- 关于安卓开发theme样式style中三个重要颜色colorPrimary、colorPrimaryDark、colorAccent
- 【dotnet跨平台】关于VS Code扩展和主题市场
- QgsApplication的功能总结
- 我们能拥有孩子多少年?
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
肾里面有囊肿怎么办
潘多拉链子长了怎么办
平板蓝屏开不了怎么办
被棕黑锦蛇咬了怎么办
吉娃娃不吃狗粮怎么办
吉娃娃耳朵不立怎么办
观音莲长高了怎么办
玉露长高了怎么办
樱水晶徒长了怎么办
秀妍徒长了怎么办
玉露叶片松散怎么办
仙人球长歪了怎么办
小鹿犬有皮屑怎么办
如果做传销被骗怎么办
观音莲叶子发黄怎么办
幸福树枝条下垂怎么办
养金鱼没有气泵怎么办
鱼缸显示器坏了怎么办
鰟鲏没有河蚌怎么办
热带鱼尾巴烂了怎么办
渔夫帽大了怎么办
渔夫帽容易掉怎么办
罗汉鱼不吃饲料怎么办
鞋子前面磨袜子怎么办
皮鞋硬磨破袜子怎么办
新鸟不服笼怎么办
兔子生宝宝了怎么办
比熊毛发黄怎么办
兔兔拉肚子了怎么办
蛇胆疮疼痛难忍怎么办
蛇胆疮后遗症疼怎么办
娃娃干咳嗽厉害怎么办
碰碰香木质化怎么办
毒蚂蚁咬了怎么办
被蚂蚁咬过敏怎么办
楼房家里有蚂蚁怎么办
家里有黑色蚂蚁怎么办
房子里有蚂蚁怎么办
床上有小红蚂蚁怎么办
地板有白蚁了怎么办
家里白蚁怎么办能除根