tcp 多路复用实现 两个客户端之间的通信
来源:互联网 发布:鲁迅体 知乎 编辑:程序博客网 时间:2024/05/16 13:49
/*******************************
服务器端
****************************/
#include <stdio.h>
#include <stdlib.h>#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#define BACKLOG 5
int main(int argc, char** argv){
if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);
int listenfd;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("listen error\n");
}
struct sockaddr_in srvaddr;
bzero(&srvaddr,sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(PORT);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
printf("set sock error");
}
if(bind(listenfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) < 0)
{
printf("bind error\n");
close(listenfd);
exit(1);
}
if(listen(listenfd, BACKLOG) < 0)
{
printf("listen error\n");
}
struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn;
int i;
int client[FD_SETSIZE];
for(i = 0; i < FD_SETSIZE; i++){
client[i] = -1;
}
///
int nready;
int maxfd = listenfd;
fd_set rset;
fd_set aset;
FD_ZERO(&rset);
FD_ZERO(&aset);
FD_SET(listenfd, &aset);
while(1)
{
rset = aset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
/*功能:检查多个文件描述符(socket描述符)是否就绪,当某一个描述符就绪(可读、可写或发生异常)时函数返回,可以实现输入输出多路复用
返回值:有描述符就绪则返回就绪的描述符个数;超时时间内没有描述符就绪返回0;执行失败返回 -1
*/
if (nready == -1)
{
if(errno == EINTR){
continue;
}
printf("select error\n");
}
if (nready == 0)///描述符就绪
{
continue;
}
int conn1;
if(FD_ISSET(listenfd, &rset)) {//如果描述符就绪
peerlen = sizeof(peeraddr);
if((conn = accept(listenfd, (struct sockaddr*) &peeraddr, &peerlen)) < 0)//如果监听端口就绪 来一个用户监听一个用户 并把返回的值给conn
{
printf("accept error");//接收失败
}
FD_SET(conn, &aset);
for(i = 0; i <FD_SETSIZE; i++)//每来一个用户fd_setsize -1
{
if(client[i] < 0)
{
client[i] = conn;
if( i > maxfd)
maxfd = i;
break;
}
}
if(i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("received from client by accept: %s, %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
if(conn > maxfd)
maxfd = conn;
if(--nready <= 0)
continue;
}
char recvbuf[1024];
char sendbuf[1024];
for(i = 0 ; i < maxfd ; i++){
conn = client[i];
conn1 = client[i+1];
/*********************************
文件描述符相当与指针 指向不同客户端
检查文件描述符conn是否可以准备 如果是
从文件描述符conn发送到conn1 实现conn向conn1发送信息
如果不是 看conn1是否就绪 如果是
从文件描述符conn1发送到conn 实现conn1向conn发送信息
*********************************/
if(FD_ISSET(conn, &rset) ){
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn, recvbuf, 1024);
if(ret == -1) {
printf("read error");
break;
}
if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}
fputs(recvbuf, stdout);
write(conn1, recvbuf, strlen(recvbuf));
if(-- nready <=0 )
{
break;
}
}
if(FD_ISSET(conn1, &rset) )
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn1, recvbuf, 1024);
if(ret == -1) {
printf("read error");
break;
}
if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}
fputs(recvbuf, stdout);
write(conn, recvbuf, strlen(recvbuf));
if(-- nready <=0 )
{
break;
}
}
}
}
}
/*********************************
客户端
******************************/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
//这个函数就是用来发送信息到服务器
void echo_cli(int sock)
{
fd_set rset;
FD_ZERO(&rset);
// jiancedao shijian geshu
int nready;
int fd_stdin = fileno(stdin);
int maxfd;
if(fd_stdin > sock)
{
maxfd = fd_stdin;
} else
{
maxfd = sock;
}
char sendbuf[1024]= {0};
char recvbuf[1024]= {0};
while(1){
FD_SET(fd_stdin, &rset);
FD_SET(sock, &rset);
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(nready == -1)
{
printf("select error");
}
if(nready == 0)
{
continue;
}
if(FD_ISSET(sock, &rset)){
int ret = read(sock, recvbuf, sizeof(recvbuf));
if(ret == 0 )
{
printf("server close\n");
break;
}
fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
}
if(FD_ISSET(fd_stdin, &rset)){
if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
break;
write(sock,sendbuf,strlen(sendbuf));
}
}
close(sock);
}
int main(int argc, char** argv){
if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
{
printf("connect error\n");
close(sock);
exit(1);
}
echo_cli(sock);
}
- tcp 多路复用实现 两个客户端之间的通信
- TCP服务器、客户端之间的相互通信
- Java基于TCP实现服务器和多客户端之间的通信
- 利用多线程和TCP技术,实现客户端与服务端之间的通信
- 实现客户端和服务器之间的通信(TCP协议、多线程)
- TCP实现客户端和服务器的通信
- 两个客户端通信的socket简单实现
- JS实现两个页面之间的通信
- LINUX 实现两个进程之间的通信
- 基于TCP的客户端与服务器端之间的通信
- C#基于TCP&UDP实现服务器与多个客户端之间的通信(客户端之间直接通信,不靠服务器端转发消息)
- 多线程TCP通信(客户端之间的数据共享)
- C++ 简单的 Tcp 实现[socket] 客户端与客户端通信
- C++ 简单的 Tcp 实现[socket] 客户端与客户端通信
- C++ 简单的 Tcp 实现[socket] 客户端与客户端通信
- 串行通信总结(实现两个单片机之间的通信)
- 用多路复用I/O模型实现支持多个客户端的通信服务
- 用多路复用I/O模型实现支持多个客户端的通信服务
- 一个完整的福利项目Kotlin,Java
- 【Android】【InputMethod】隐藏输入法
- c++中move constructor and assignment
- 《实用软件工程》视频笔记(二)
- SpringBoot第一个坑
- tcp 多路复用实现 两个客户端之间的通信
- react 组件
- git命令
- ListView实现多级树形菜单
- Koa
- Spring Boot 使用Oracle集成Mybatis,驼峰映射(下划线)问题
- [组合] Codeforces #575H. Bots
- 2017年中国家用电器技术大会,物联网+人工智能将对家电产业产生新价值
- redis auth