服务器代码段如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 6666 //自定义服务器连接客户端的端口号,1~1024已被占用,故必须大于
#define SIZE 1000 //1024
int sockfd; //定义一个套接字
struct info //定义一个结构体存放需要转发的信息的来源和指向,信息内容
{
int fromfd;
int tofd;
char buf[32];
};
typedef struct info Info;
void *recvhand(void *arg) //线程处理函数
{
int ret;
Info recvbuf;
int fd = *(int *)arg; //传过来的参数类型必须强转变为int类型文件描述符
pthread_detach(pthread_self()); //线程分离,该线程自己结束后自己回收
while(1)
{
memset(&recvbuf, 0, sizeof(recvbuf)); //结构体初始化即清空
ret = recv(fd, &recvbuf, sizeof(recvbuf), 0); //接收信息至结构体
recvbuf.fromfd = fd; //将发来信号的客户端的文件
if(-1 == ret) //描述符进行保存发送给另一个客户端
{
perror("recv");
}
if(!strcmp(recvbuf.buf, "bye")) //当接受到的数据是bye时聊天结束
{ //关闭此客户端信号
printf("%d is unline!\n", recvbuf.fromfd);
close(fd);
break;
}
ret = send(recvbuf.tofd, &recvbuf, sizeof(recvbuf), 0);
if(-1 == ret) //将接受到的数据发送给另一个待接受的客户端
{
perror("send");
}
}
}
int main()
{
int ret, fd[SIZE], i = 0; //fd定义为数组是因为这里控制以下最多可以连接到该
pthread_t tid; //服务器的客户端总数
sockfd = socket(PF_INET, SOCK_STREAM, 0); //申请套接字,第一个参数为ipv4协议,
if(sockfd == -1) //第二个参数为流式套接字属性,第三个默认为0即可
{
perror("socket");
exit(1);
}
struct sockaddr_in servers; //定义一个用于存储服务器信息的结构体
memset(&servers, 0, sizeof(servers)); //清空结构体
servers.sin_family = PF_INET; //结构体元素初始化
servers.sin_port = PORT;
servers.sin_addr.s_addr = inet_addr("192.168.1.111"); //此ip地址为服务器所在的网段
//的ip地址
ret = bind(sockfd, (struct sockaddr *)&servers, sizeof(servers));
if(-1 == ret) //将服务器套接字与刚刚初始化的ip进行连接绑定
{
perror("bind");
exit(1);
}
ret = listen(sockfd, 5); //创建一个监听队列,监听正在等待连接的客户端,
if(ret < 0) //第二个参数为等待连接的最大数目
{
perror("listen");
exit(1);
}
int len = sizeof(servers);
while(1) //这里用一个循环随时准备接受连接信号,每接受一个连接信号
{ //就创建一个线程来处理该客户端
printf("waitting connecting...\n");
fd[i] = accept(sockfd, (struct sockaddr *)&servers, &len);
if(-1 == fd[i]) //注意需创建一个独立的文件描述符来接受处理
{ //发出信号的客户端
perror("accept");
exit(1);
}
ret = pthread_create(&tid, NULL, recvhand, &fd[i]); //创建一种线程处理方式
if(-1 == ret)
{
perror("pthread_create");
exit(1);
}
printf("connecting success fd: %d port: %d\n", fd[i], servers.sin_port);
i++;
}
close(sockfd);
return 0;
}
客户端代码段如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
int sockfd;
pthread_t tid1, tid2;
struct info
{
int fromfd;
int tofd;
char buf[32];
};
typedef struct info Info;
#define PORT 6666 //这个端口号必须是服务器的端口号
void signalquit()
{
Info sendbuf;
strcpy(sendbuf.buf, "bye"); //在自己关闭的同时必须要告知服务器让服务器也关闭
sendbuf.fromfd = sockfd; //对应的线程
send(sockfd, &sendbuf, sizeof(sendbuf), 0);
close(sockfd);
pthread_cancel(tid2); //把线程关闭掉
exit(1);
}
void *sendpthread(void *arg) //线程发送函数
{
int ret;
int fd = *(int *)arg;
Info sendbuf;
while(1)
{
memset(&sendbuf, 0, sizeof(sendbuf));
scanf("%d%s", &sendbuf.tofd, sendbuf.buf);
ret = send(fd, &sendbuf, sizeof(sendbuf), 0);
if(ret == -1)
{
perror("send");
}
}
}
void *recvpthread(void *arg) //线程接收函数
{
int ret;
int fd = *(int *)arg;
Info recvbuf;
int old;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
while(1)
{
memset(&recvbuf, 0, sizeof(recvbuf));
ret = recv(fd, &recvbuf, sizeof(recvbuf), 0);
if(ret == -1)
{
perror("recv");
}
printf("from %d : %s\n", recvbuf.fromfd, recvbuf.buf);
}
}
int main()
{
int ret;
signal(SIGINT, signalquit); //接受到Ctrl C信号后执行函数signalquit
sockfd = socket(PF_INET, SOCK_STREAM, 0); //创建流式套接字
if(sockfd == -1)
{
perror("sockfd");
exit(1);
}
struct sockaddr_in client; //创建一个结构体保存客户端信息
memset(&client, 0, sizeof(client)); //结构体初始化与赋值
client.sin_family = PF_INET;
client.sin_port = PORT;
client.sin_addr.s_addr = inet_addr("192.168.1.111"); //这里的ip必须是服务器的ip
ret = connect(sockfd, (struct sockaddr *)&client, sizeof(client));
if(-1 == ret) //向服务器申请连接
{
perror("connect");
exit(1);
}
ret = pthread_create(&tid1, NULL, sendpthread, &sockfd);//创建一个发送线程
if(-1 == ret)
{
perror("pthread_create");
exit(1);
}
ret = pthread_create(&tid2, NULL, recvpthread, &sockfd);//创建一个接收线程
if(-1 == ret)
{
perror("pthread_create");
exit(1);
}
void *status;
pthread_join(tid1, &status); //回收线程
pthread_join(tid2, &status);
close(sockfd);
return 0;
}