c 实现两个tcp连接数据转发

// testserver.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
/* For sockaddr_in */
#include 
/* For socket functions */
#include 
/* For fcntl */
#include 
/* for select */
#include 

#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_LINE 16384


struct fd_state {
	char buffer[MAX_LINE];
	size_t buffer_used;

	int writing;
	size_t n_written;
	size_t write_upto;
};

struct fd_state *
	alloc_fd_state(void)
{
	struct fd_state *state = malloc(sizeof(struct fd_state));
	if (!state)
		return NULL;
	state->buffer_used = state->n_written = state->writing =
		state->write_upto = 0;
	return state;
}

void
free_fd_state(struct fd_state *state)
{
	free(state);
}

void
make_nonblocking(int fd)
{
	fcntl(fd, F_SETFL, O_NONBLOCK);
}



int
do_onlyread(int fd, struct fd_state *state)
{
	char buf[1024];
	int i;
	ssize_t result;
	while (1) {
		result = recv(fd, buf, sizeof(buf), 0);

		if (result <= 0)
			break;

		printf("read %s from fd %d \n", buf, fd);

	}

	if (result == 0) {
		return 1;
	}
	else if (result < 0) {
		if (errno == EAGAIN)
			return 0;
		return -1;
	}

	return 0;
}













int
do_read(int fd, struct fd_state *state)
{
	char buf[1024];
	int i;
	ssize_t result;
	while (1) {
		result = recv(fd, buf, sizeof(buf), 0);

		if (result <= 0)
			break;



		for (i = 0; i < result; ++i) {
			if (state->buffer_used < sizeof(state->buffer))
				state->buffer[state->buffer_used++] = buf[i];
			if (buf[i] == '\n') {
				state->writing = 1;
				state->write_upto = state->buffer_used;
				state->buffer[state->buffer_used] = 0;
				//printf("read %s from fd %d \n  ", buf,fd);
			}
		}
	}

	if (result == 0) {
		return 1;
	}
	else if (result < 0) {
		if (errno == EAGAIN)
			return 0;
		return -1;
	}

	return 0;
}

int
do_write(int fd, struct fd_state *state)
{
	while (state->n_written < state->write_upto) {
		ssize_t result = send(fd, state->buffer + state->n_written,
			state->write_upto - state->n_written, 0);
		if (result < 0) {
			if (errno == EAGAIN)
				return 0;
			return -1;
		}
		assert(result != 0);

		state->n_written += result;
	}

	if (state->n_written == state->buffer_used)
		state->n_written = state->write_upto = state->buffer_used = 0;

	state->writing = 0;

	return 0;
}

void
run(void)
{
	int listener;
	struct fd_state *state[FD_SETSIZE];
	struct sockaddr_in sin;
	int i, maxfd;
	fd_set readset, writeset, exset;

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = 0;
	sin.sin_port = htons(40713);

	for (i = 0; i < FD_SETSIZE; ++i)
		state[i] = NULL;

	listener = socket(AF_INET, SOCK_STREAM, 0);
	make_nonblocking(listener);

#ifndef WIN32
	{
		int one = 1;
		setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	}
#endif

	if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
		perror("bind");
		return;
	}

	if (listen(listener, 2)<0) {
		perror("listen");
		return;
	}

	FD_ZERO(&readset);
	FD_ZERO(&writeset);
	FD_ZERO(&exset);

	while (1) {
		maxfd = listener;

		FD_ZERO(&readset);
		FD_ZERO(&writeset);
		FD_ZERO(&exset);

		FD_SET(listener, &readset);

		for (i = 0; i < FD_SETSIZE; ++i) {
			if (state[i]) {
				if (i > maxfd)
					maxfd = i;
				FD_SET(i, &readset);
				if (state[i]->writing) {
						FD_SET(i, &writeset);
					//else
					//FD_SET(i, &writeset);
				}
			}
		}

		if (select(maxfd + 1, &readset, &writeset, &exset, NULL) < 0) {
			perror("select");
			return;
		}

		if (FD_ISSET(listener, &readset)) {
			struct sockaddr_storage ss;
			socklen_t slen = sizeof(ss);
			int fd = accept(listener, (struct sockaddr*)&ss, &slen);
			if (fd < 0) {
				perror("accept");
			}
			else if (fd > 5) {
				printf("only support 2 file fd %d closed\n", fd);
				close(fd);
			}
			else {
				printf("fd %d connect\n", fd);
				make_nonblocking(fd);
				state[fd] = alloc_fd_state();
				assert(state[fd]);/*XXX*/
			}
		}

		for (i = 0; i < maxfd + 1; ++i) {
			int r = 0;
			if (i == listener)
				continue;

			if (FD_ISSET(i, &readset)) {
				if ((i == 4) && (state[5]!=NULL))
					r = do_read(i, state[5]);
				else if((i == 5) &&(state[4]!=NULL))
					r = do_read(i, state[4]);
				else
					r = do_onlyread(i, state[i]);
			}

			if (r) {
				free_fd_state(state[i]);
				state[i] = NULL;
				printf("fd %d closed\n", i);
				close(i);
				
			}

			r = 0;
			if (FD_ISSET(i, &writeset)) {
				printf("fd %d wirte ", i);
				r = do_write(i, state[i]);
			}

			if (r) {
				free_fd_state(state[i]);
				state[i] = NULL;
				printf("fd %d closed\n", i);
				close(i);
			}



		}
	}
}

int
main(int c, char **v)
{
	setvbuf(stdout, NULL, _IONBF, 0);

	run();
	return 0;
}

python测试程序

# -*- coding: utf-8 -*-
'''
This is a testing program
the program is used to test socket client
'''
import socket
import sys
import threading


def tcprecv(tcp_client):
    while True:
        (message, address) = tcp_client.recvfrom(8192)
        print("Got data from", str(tcp_client.getpeername()), ": ", message.decode())

def start_tcp_client(ip, port):
  #server port and ip
  server_ip = ip
  server_port = port
  tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  serveraddr = (server_ip,server_port)
  try:
    tcp_client.connect(serveraddr)
  except socket.error:
    print( 'fail to setup socket connection')
    return

  rthread = threading.Thread(target=tcprecv,args=(tcp_client,))
  rthread.start()

  while True:
      msg = input()
      if not msg:
          break
      msg = msg+'\n'
      tcp_client.send(msg.encode())
  tcp_client.close()

start_tcp_client("xx.xx.xx.xx",40713)

 

你可能感兴趣的:(c 实现两个tcp连接数据转发)