客户端多线程接收服务器信息,【原创】多线程实现:服务器发送消息时,所有客户端可收到。客户端发送信息时,只服务器可收到...

多线程实现

需求:

1、实现服务器与客户端的通信,服务器可接收多个客户端。

2、服务器发送消息时,所有客户端都可收到。

3、客户端发送信息时,只有服务器可收到。

4、服务器发送“bye”时,包括服务器程序及所有客户端程序都结束,客户端发送“bye”时,本客户端结束(当然,服务器对应的线程也会结束)。

5、服务器要在输出客户端消息时,要连同对应客户端的IP一起输出。

对于上述需求,对应序号的解决方法如下:

1. 选用TCP(UDP也可)进行通信,主进程监听并创建与客户端对应的线程

2. 分为main(),发送信息线程处理函数,接受信息线程处理函数。

具体:

只要有一个接受客户端,就要创建服务器发送信息线程,为了编写的方便,也可没有接受客户端就创建服务器发送信息线程,只要服务器端有输入,就要向每个客户端发送,这就要求服务器发送线程能对主进程创建的所有客户端socket文件描述符,进行操作(写操作)。所以全局变量需包括所有socket描述符(也可在main中定义而传地址)。但是,如何判断某个socket文件描述符是否关闭、可用,就要在初始时,将socket文件描述符置为0或负数,并且当对应的客户端线程关闭前,需要close(socket)后,置socket为0或负数。当服务器端读取到字符串后,就遍历整个socke数组,判断是否大于0,大于就发送信息到此socket描述符。

3. 正常解决

4. 在客户端、服务器端发送完信息后,都将此信息与”bye”比较,是“bye“就退出。

5. 在服务器accept一个客户端后,需要将得到的客户端地址IP记录,并传递给将要创建的与此客户端交互的线程

6. 由2、5可得到,传递给服务器接受信息线程的参数为:socket文件描述符,IP

//server.c

#include

#include

#include //struct

sockaddr_in

#include

#include

#include

#include

#include

#include

#include

#define PORT 5000

#define A(x) (struct sockaddr*)(&x)

#define ACCEPT_NUM 5

pthread_t m_id;//send massage's pthread_id

pthread_t id[ACCEPT_NUM];//thread num

struct thread_arg{

int fd; //指向同一个文件描述符

char ip[100];

};

struct thread_arg arg[ACCEPT_NUM];//向recv_func传递的参数类型

char server_massage[1024]={0};

//int thread_num=0;//已经存在的线程数

//recv_ massage

void* recv_func(void* p)

{

int i=(int)p;

char buf[1000];

int readn=0;

for(;;){

memset(buf,0,sizeof(buf));

readn=read(arg[i].fd,buf,sizeof(buf)-1);//读取客户端来的信息

if(readn<=0) break;//出错或者对方关闭就退出

buf[readn] = '\0';

printf("clientip-%s  :

%s\n",arg[i].ip,buf);

if(strncmp(buf,"bye",3)==0) break;

}

close(arg[i].fd);

arg[i].fd=0;//说明对应描述符已经关闭,易于send_massage线程的判断

}

void* send_massage(void*para){

int nread=-1;

int i=0;

while((nread=read(0,server_massage,sizeof(server_massage)))){

server_massage[nread]='\0';

for(i=0;i

if(arg[i].fd>0){

write(arg[i].fd,server_massage,strlen(server_massage)+1);

}

}

if(strncmp(server_massage,"bye",3)== 0)

{

exit(0);

}

}

}

int main()

{

int server_sock;

server_sock = socket(AF_INET, SOCK_STREAM, 0);//建立套接字

struct sockaddr_in si;

si.sin_family = AF_INET;//跟前面的一致

si.sin_addr.s_addr = INADDR_ANY;//0,本机的任何ip

si.sin_port = htons(PORT);

if(bind(server_sock, A(si),

sizeof(si))<0){

printf("%s\n",strerror(errno));exit(1);

}

pthread_create(&m_id,NULL,send_massage,NULL);

listen(server_sock, 5);

int j=0;

for(j=0;j

{

socklen_t len = sizeof(si);

arg[j].fd =

accept(server_sock,A(si),&len);//等待客户端连接

if(arg[j].fd<0)

{

perror("accept failed");

return -1;

}

//成功就返回新套接字

//welcome friend from

char buf[100], ip[100];

inet_ntop(si.sin_family,&si.sin_addr,ip,sizeof(ip));

printf("%s到此一游\n", ip);

sprintf(buf,"welcome friend from

\n",

ip,ntohs(si.sin_port));

write(arg[j].fd,buf,strlen(buf));

memcpy(arg[j].ip,ip,100);

pthread_create(&id[j],NULL,recv_func,(void*)j);

// thread_num++;

}

pthread_join(m_id,NULL);

}

//client

//client

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 5000  // The port

which is communicate with server

#define LENGTH 1024  // Buffer length

void* send_massage(void *);

void* recv_massage(void* );

int main(int argc, char *argv[])

{

int sockfd;

// Socket

file descriptor

int num;

// Counter of received bytes

int

recv_pid;

int send_pid;

struct sockaddr_in

remote_addr;  // Host address

information

if (argc != 2)

{

printf ("Usage: client SERVER_IP (ex: ./client

192.168.0.94).\n");

return (0);

}

if ((sockfd =

socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

printf("ERROR: Failed to obtain Socket

Descriptor!\n");

return (0);

}

remote_addr.sin_family =

AF_INET;  //

Protocol Family

remote_addr.sin_port =

htons(PORT);  // Port

number

inet_pton(AF_INET,

argv[1], &remote_addr.sin_addr); // Net

Address

if (connect(sockfd,

(struct sockaddr *)&remote_addr,

sizeof(struct sockaddr)) == -1)

{

printf ("ERROR: Failed to connect to the

host!\n");

return (0);

}

else

{

printf ("OK: Have connected to the

%s\n",argv[1]);

}

pthread_create(&send_pid,NULL,send_massage,(void*)sockfd);

pthread_create(&recv_pid,NULL,recv_massage,(void*)sockfd);

pthread_join(send_pid,NULL);

pthread_join(recv_pid,NULL);

return (0);

}

//thread_to recv massaga

void* recv_massage(void* arg)

{

char revbuf[LENGTH]={0};  // Receive buffer

int sockfd=(int )arg;

int num;

memcpy(revbuf,"hello",6);

while

(strncmp(revbuf,"bye",3) != 0)  // Check remoter command

{

memset(revbuf,0,LENGTH);

num = read(sockfd, revbuf, LENGTH);

if(num<=0){

exit(0);

}

revbuf[num]='\0';

printf("server: %s \n",revbuf);

}

exit(0);

}

//thread to send massage

void* send_massage(void *arg)

{

int fd=(int)arg;

char sendbuf[LENGTH]={0};

int nread=0;

while(1){

printf("please input some word:\n");

//scanf("%s",sendbuf);

nread=read(0,sendbuf,LENGTH);

if(nread<=0)

{

exit(0);

}

sendbuf[nread]='\0';

write(fd,sendbuf,strlen(sendbuf)+1);

if(strncmp(sendbuf,"bye",3)==0)

{

exit(0);

}

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值