多客户机通信的小结:
/***********************************/
服务器需要调用的函数:socket,bind,listen,accept
bind把服务器和sockfd捆绑,accept是listen之后有客户机请求连接,返回客户的信息fd,服务器就是对fd进行send和recv
客户机需要调用的函数:socket,connect
先connect 客户机去连接服务器,连接之后是利用客户机socket函数的返回值sockfd进行通信
/***********************************/
connectt和bind之前要
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
/*****************************/
Tcp为了数据的准确性会进行多次握手和挥手这期间需要时间,在socket之后,有了下面的函数,不会出现下一次运行程序要等待的情况
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/*************************/
注意创建线程的时候传参的问题
/*********************/
/*
struct sockaddr_in{
shaor sin_family; //地址族
u_short sin_port; //端口
struct in_addr sin addr; //IP地址
char sin_size[8]; //用于补充,使得结构体和struct sockaddr大小相同
};
struct in_addr{
in_addr_t s_addr;
};
*/
/*******************************/
创建多个客户机的时候在
在listen函数之前加while(1)死循环,但是但是由于pthread_join函数阻塞,
只有与第一个客户机通信线程运行结束的时候才能进入下一次循环,创建新的客户机,这样就不符合常理,不能实现多个客户机的通信
调用函数pthread_detach(pthread_self());可以让线程运行结束的时候自行回收资源,去掉pthread_join函数
/*************************************/
服务器先接受客户机发送的结构体,之后解析结构体info.fd知道是要发送到哪一个客户机,之后只要把相应的text发送过去就行
客户机先录入要发送给谁,发送什么内容,把整个结构体发送过去
客户机接收的时候,只需要一个buf用来接收,不需要对结构体进行操作,因为发送的客户机经过服务器已经把结构体解析了,服务器发送过来的就是text
1.
客户机和服务器聊天出现的问题
void *client_send(void *arg)函数内忘了scanf("%s", buf);程序没有输入的语句;
memset(buf, 0, sizeof(buf));对buf进行了&操作;
if((!strncmp(buf,"exit",4)))忘了!程序编译的时候好像就出错了
server_addr.sin_family = PF_INET;把server_addr写成sockaddr_in编译报错没有sockaddr_in,找错好长时间
printf("waiting...\n");忘了\n运行时发送有问题
/**********sever.c****************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#define PORT 2222
pthread_t {
int ret;
char buf[100] = {0};
while (1)
{
memset(buf, 0, sizeof(buf));
scanftid1, tid2;
void *client_send(void *arg)
("%s", buf);
ret = send((int)arg, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("send");
exit(1);
}
if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid2);
return (void *)0;
}
}
return (void *)0;
}
void *client_recv(void *arg)
{
char buf[100] = {0};
int ret;
while (1)
{
ret = recv((int)arg, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv");
exit(1);
}
if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid1);
return (void *)0;
}
printf("\t\t\t%s\n", buf);
}
return (void *)0;
}
int main()
{
int sockfd, ret, addr_len, fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
void *thread_ret;
printf("Start server!\n");
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("bind");
exit(1);
}
printf("Waiting...\n");
while (1)
{
ret = listen(sockfd, 5);
if (-1 == ret)
{
perror("listen");
exit(1);
}
memset(&client_addr, 0, sizeof(client_addr));
addr_len = sizeof(client_addr);
fd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len);
if (-1 == ret)
{
perror("accept");
exit(1);
}
printf("accept success!\n");
pthread_create(&tid1, NULL, client_send, (void *)fd);
pthread_create(&tid2, NULL, client_recv, (void *)fd);
/*pthread_join(tid1, &thread_ret);
pthread_join(tid2, &thread_ret);*/
}
close(fd);
close(sockfd);
return 0;
}
/************client.c************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#define PORT 2222
pthread_t tid1, tid2;
void *client_send(void *arg)
{
int ret;
char buf[100] = {0};
while (1)
{
memset(buf, 0, sizeof(buf));
scanf("%s", buf);
ret = send((int)arg, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("send");
exit(1);
}
if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid2);
return (void *)0;
}
}
return (void *)0;
}
void *client_recv(void *arg)
{
char buf[100] = {0};
int ret;
while (1)
{
ret = recv((int)arg, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv");
exit(1);
}
if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid1);
return (void *)0;
}
printf("\t\t\t%s\n", buf);
}
return (void *)0;
}
int main(int argc, char *argv[])
{
int ret, sockfd;
struct sockaddr_in server_addr;
void *thread_ret;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("connect");
exit(1);
}
pthread_create(&tid1, NULL, client_send, (void *)sockfd);
pthread_create(&tid2, NULL, client_recv, (void *)sockfd);
pthread_join(tid1, &thread_ret);
pthread_join(tid2, &thread_ret);
return 0;
}
2/********************************/
多个客户机和服务器通信,但是服务器发的消息只能到达第一个客户机,所有的客户机发送的消息服务器都能收到
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#define PORT 2222
pthread_t tid1,tid2;
void *client_send(void * arg)
{
char buf[100] = {0};
int ret;
pthread_detach(pthread_self()); //使用之后自动回收内存
while(1)
{
memset(buf,0,sizeof(buf));
scanf("%s",buf);
/*send参数1指定发送端套接字描述符 2.应用程序要发送的数据的缓冲区
3.实际要发送的数据字节数 4一般是0*/
ret = send((int)arg,buf,sizeof(buf),0); //从客户端发送数据到buf
if(-1 == ret)
{
perror("send");
exit(1);
}
/*****************************/
if(!strncmp(buf,"exit",4))
{
pthread_cancel(tid2);
return (void*)0;
}
}
}
void *client_recv(void *arg)
{
char buf[100] = {0};
int ret;
pthread_detach(pthread_self());
while(1)
{
/*不管服务器还是客户都要recv函数从tcp链接的另一端接收数据
参数 1.指定接收端套接字描述符 2。指明缓冲区,用来存放recv接收到的数据
3.指明buf的长度 4.一般设置0
*/
ret = recv((int)arg,buf,sizeof(buf),0); //服务器端接收数据
if(-1 == ret)
{
perror("recv");
exit(1);
}
/*****************************/
if(!strncmp(buf,"exit",4))
{
pthread_cancel(tid1);
return (void*)0;
}
printf("\t\t\t%s\n",buf);
}
}
int main()
{
int ret,addr_len;
int fd,sockfd;
struct sockaddr_in server_addr; //结构体
struct sockaddr_in client_addr; //结构体
//pthread_t tid1,tid2;
void * pthread_ret;
/*socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,
应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1
*/
sockfd = socket(PF_INET,SOCK_STREAM,0); //sockfd网络文件描述符
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
/*bind()的作用是将参数sockfd和myaddr绑定在一起,使sockfd这个用于网络通讯的文件描述符
监听myaddr所描述的地址和端口号
将将服务器的ip地址,端口等信息和sockfd绑定
*/
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
if(-1 == ret)
{
perror("bind");
exit(1);
}
printf("waiting...\n");
while(1)
{
ret = listen(sockfd,5);
if(-1 == ret)
{
perror("listen");
exit(1);
}
/* 三方插手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,
就阻塞等待直到有客户端连接上来,cliaddr是一个传出参数,accept()返回时传出客户端的地址和端口号*/
memset(&client_addr,0,sizeof(client_addr));
addr_len = sizeof(client_addr);
fd = accept(sockfd,(struct sockaddr*)&client_addr,&addr_len); //fd客户端的地址和端口号
if(-1 == fd)
{
perror("accept");
exit(1);
}
printf("accept!\n");
pthread_create(&tid1,NULL,client_send,(void*)fd); //last canshu NULL ?
pthread_create(&tid2,NULL,client_recv,(void*)fd);
}
//pthread_join(tid1,&pthread_ret);
//pthread_join(tid2,&pthread_ret);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#define PORT 2222
int fd,sockfd;
pthread_t tid1,tid2;
void *client_send(void * arg)
{
char buf[100] = {0};
int ret;
while(1)
{
memset(buf,0,sizeof(buf));
scanf("%s",buf);
ret = send((int)arg,buf,sizeof(buf),0); //first canshu
if(-1 == ret)
{
perror("send");
exit(1);
}
/*****************************/
if(!strncmp(buf,"exit",4))
{
pthread_cancel(tid2);
return (void*)0;
}
}
}
void *client_recv(void *arg)
{
char buf[100] = {0};
int ret;
while(1)
{
ret = recv((int)arg,buf,sizeof(buf),0); //first canshu
if(-1 == ret)
{
perror("recv");
exit(1);
}
/*****************************/
if(!strncmp(buf,"exit",4))
{
pthread_cancel(tid1);
return (void*)0;
}
printf("\t\t\t%s\n",buf);
}
}
int main()
{
int ret,addr_len;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
// pthread_t tid1,tid2;
void * pthread_ret;
sockfd = socket(PF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
/*客户端需要调用connect()连接服务器,connect的参数是对方的地址.
参数 1.客户端的套接字(表明即将发起连接请求) 2.服务器的套接字所在的地方(自我定义的专有名词)
3.长度
*/
ret = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));//成功返回0
if(-1 == ret)
{
perror("connect");
exit(1);
}
/*memset(&client_addr,0,sizeof(client_addr));
addr_len = sizeof(client_addr);
fd = accept(sockfd,(struct sockaddr*)&client_addr,&addr_len); //qiangzhuan _kenneg shaole
if(-1 == fd)
{
perror("accept");
exit(1);
}*/
//pthread_create(&tid1,NULL,client_send,(void*)fd); //last canshu NULL ?
//pthread_create(&tid2,NULL,client_recv,(void*)fd);
pthread_create(&tid1, NULL, client_send, (void *)sockfd);
pthread_create(&tid2, NULL, client_recv, (void *)sockfd);
pthread_join(tid1,&pthread_ret);
pthread_join(tid2,&pthread_ret);
return 0;
}
3
客户机和客户机的通信
pthread_detach(pthread_self());把detach写成cancel
注意void *client(void *arg)函数内什么时候发送text什么发送整个结构体
!!!!!!!!!!!!!!!!!!!!i++;写到pthread_create(&tid1, NULL, client, (void *)fd[i]);前面导致客户机程序无限死循环,就连scanf都不执行
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
之前不要忘了 memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#define PORT 2222
#define MAX_CLIENT 100
struct information {
int fd;
char text[100];
};
pthread_t tid1, tid2;
void *client(void *arg)
{
int ret;
int to;
struct information info;
pthread_detach(pthread_self());
while (1)
{
memset(&info, 0, sizeof(info));
ret = recv((int)arg, (void *)&info, sizeof(info), 0);
if (ret < 0)
{
perror("send");
exit(1);
}
to = info.fd;
ret = send(to, (void *)info.text, sizeof(info.text), 0);
if (ret < 0)
{
perror("send");
exit(1);
}
/*if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid2);
return (void *)0;
}*/
}
return (void *)0;
}
/*void *client_recv(void *arg)
{
char buf[100] = {0};
int ret;
pthread_detach(pthread_self());
while (1)
{
ret = recv((int)arg, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv");
exit(1);
}
if (!strncmp(buf, "exit", 4))
{
pthread_cancel(tid1);
return (void *)0;
}
printf("\t\t\t%s\n", buf);
}
return (void *)0;
}*/
int main()
{
int sockfd, ret, addr_len;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
void *thread_ret;
int i = 0;
int fd[MAX_CLIENT] = {0};
printf("Start server!\n");
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("bind");
exit(1);
}
printf("Waiting...\n");
while (1)
{
ret = listen(sockfd, 5);
if (-1 == ret)
{
perror("listen");
exit(1);
}
memset(&client_addr, 0, sizeof(client_addr));
addr_len = sizeof(client_addr);
fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len);
if (-1 == ret)
{
perror("accept");
exit(1);
}
printf("accept success fd = %d!\n", fd[i]);
pthread_create(&tid1, NULL, client, (void *)fd[i]);
i++;
}
close(fd);
close(sockfd);
return 0;
}