用网络TCP实现交流

服务器代码段如下:

#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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值