365bet体育娱乐-大陆365bet网址-365bet是合法的

Linux使用tcp实现点对点通信

Linux使用tcp实现点对点通信

1、概述

通常tcp客户端连接服务器,服务器先调用listen处于监听状态,然后客户端调用connect连接服务器,建立连接,对应的3次握手如图:

但是如果不调用listen能否完成3次握手,建立连接呢?答案是可以建立连接的,tcp点对点通信就是这个场景。

tcp实现点对点通信,俩个tcp客户端直接连接,没有服务器,互发数据。不调用listen,accept函数。对应的3次握手图如下:

2、代码如下

思路:

fd = socket();

bind(fd,port);

connect();

send/recv();

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define BUFF_SIZE 1024

typedef int (*RCALLBACK)(int fd);

int epfd = 0;

enum _EPOLL_CTL

{

ADD = 0,

MOD

};

// fd相关事件结构体

struct fd_event {

int fd;

char rbuf[BUFF_SIZE];

int rLen;

char wbuf[BUFF_SIZE];

int wLen;

// 回调函数

union

{

RCALLBACK read_callback;

} r_action;

RCALLBACK send_callback;

} connect_event;

int set_event(int fd, int event, enum _EPOLL_CTL flag)

{

struct epoll_event ev;

ev.events = event;

ev.data.fd = fd;

if (ADD == flag)

{

epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

}

else if (MOD == flag)

{

epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);

}

}

int recv_cb(int confd)

{

memset(connect_event.rbuf, 0, sizeof(connect_event.rbuf));

int count = recv(confd, connect_event.rbuf, sizeof(connect_event.rbuf), 0);

if (count == 0)

{

epoll_ctl(epfd, EPOLL_CTL_DEL, confd, NULL);

close(confd);

}

connect_event.rLen = count;

printf("Received message: %s\n", connect_event.rbuf);

return count;

}

int send_cb(int confd)

{

int count = send(confd, connect_event.wbuf, connect_event.wLen, 0);

set_event(confd, EPOLLIN, MOD);

return count;

}

void* thread_func(void* arg)

{

int fd = *(int*)arg;

while (1) {

scanf("%s", connect_event.wbuf);

connect_event.wLen = strlen(connect_event.wbuf);

if (strcmp(connect_event.wbuf, "quit") == 0)

{

break;

}

set_event(fd, EPOLLOUT, MOD);

}

close(fd);

}

int main(int argc, char** argv)

{

if (argc <=2 )

{

printf("Usage: %s \n", argv[0]);

exit(1);

}

char* ip = argv[1];

int port = atoi(argv[2]);

printf("ip:%s, port:%d\n", ip, port);

int socketfd = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in addr;

memset(&addr, 0, sizeof(struct sockaddr_in));

addr.sin_family = AF_INET;

addr.sin_addr.s_addr = htonl(INADDR_ANY);// inet_addr("0.0.0.0");//htonl(INADDR_ANY);

addr.sin_port = htons(port); // 0-1023 系统默认端口 1024~65535 用户端口

// 绑定

if(-1 == bind(socketfd, (struct sockaddr*)&addr, sizeof(addr)))

{

printf("bind error errno:%s\n", strerror(errno));

return -1;

}

printf("bind success\n");

epfd = epoll_create(1);

struct sockaddr_in serveraddr;

memset(&serveraddr, 0, sizeof(struct sockaddr_in));

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.s_addr = inet_addr(ip);//htonl(INADDR_ANY);

serveraddr.sin_port = htons(port); // 0-1023 系统默认端口 1024~65535 用户端口

while (1)

{

if (connect(socketfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr_in)) == 0) {

printf("connect success errno:%s\n", strerror(errno));

break;

}

//printf("connect....\n");

usleep(1000);

}

connect_event.fd = socketfd;

connect_event.rLen = 0;

connect_event.wLen = 0;

memset(connect_event.rbuf, 0, sizeof(connect_event.rbuf));

memset(connect_event.wbuf, 0, sizeof(connect_event.wbuf));

connect_event.r_action.read_callback = recv_cb;

connect_event.send_callback = send_cb;

set_event(socketfd, EPOLLIN, ADD);

// 启动一个线程处理用户输入

pthread_t tid;

pthread_create(&tid, NULL, thread_func, (void*)&socketfd);

while (1)

{

struct epoll_event events[1024];

int nready = epoll_wait(epfd, events, 1024, -1);

for (int i = 0; i < nready; i++)

{

int confd = events[i].data.fd;

if (events[i].events & EPOLLIN)

{

connect_event.r_action.read_callback(confd);

}

if (events[i].events & EPOLLOUT)

{

connect_event.send_callback(confd);

}

}

}

return 0;

}

3、编译运行

将代码分别拷贝到2个机器上,分别编译

gcc -o p2pClient p2pClient.c -lpthread

在A机器运行:./p2pClient "192.168.202.224" 3000

在B机器运行:./p2pClient "192.168.202.223" 3000

即可互相发送数据

学习链接:https://github.com/0voice