TCP端口同时做服务器与客户端

下面的代码主要实现两个功能:

1,通过bind使本机指定端口如2012端口与远端服务器通信,不指定的话会随机分配

2,然后使用该指定端口创建监听服务,接受其他客户端的连接。

主要方法用到端口复用,通过调用setsocketopt函数设置标记位实现,不进行端口复用的话程序在第二个步骤bind的时候会出现端口已被占用的错误信息

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
//远程服务器端口和IP
#define PORT 1987
#define HOST "192.168.197.118"
//本机服务器端口和IP
#define LOCALPORT 2012
#define LOCALHOST "10.0.2.15"

//线程提供TCP服务器服务,绑定2012端口
void serve_proc(int port)
{
        printf("server start listening on port %d\n",port);
        int sock_fd;

        if ((sock_fd=socket(AF_INET, SOCK_STREAM, 0))==-1){
                printf("socket() error\n");
                exit(1);
        }

        struct sockaddr_in server, client;
        bzero(&server,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        server.sin_addr.s_addr = inet_addr(LOCALHOST);
        int reuseport = 1;

        //端口设置重用,不然会bind出错
        setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseport, sizeof(int));
        if (bind(sock_fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0){
                perror("bind error");
                exit(-1);
        }
        if (listen(sock_fd,5) < 0) {
                perror("listen error");
                exit(-1);
        }

        char recv_buf[100],send_buf[100];
        int conn_fd;
        int client_size = sizeof(struct sockaddr_in);
        while(1){
                conn_fd = accept(sock_fd, (struct sockaddr *)&client, &client_size);
                if (conn_fd < 0){
                        perror("accept error");
                        exit(-1);
                }
                while(1){
                        int recv_num = recv(conn_fd, recv_buf, sizeof(recv_buf), 0);
                        if(recv_num < 0){
                                close(conn_fd);exit(-1);
                        }
                        recv_buf[recv_num] = '\0';
                        if(strcmp(recv_buf,"quit")==0){
                                break;
                        }
                        printf("server get %s\n", recv_buf);
                        sprintf(send_buf, "server got %d bytes\n", recv_num);
                        int send_num = send(conn_fd, send_buf, strlen(send_buf), 0);
                        if(send_num < 0){
                                close(conn_fd);exit(-1);
                        }
                }
                close(conn_fd);
        }
}

int main(int argc, char *argv[])
{
        int sock_fd;
        struct sockaddr_in server,client;
        int flag = 0;
        int reuseport = 1;
        int local_port = LOCALPORT;

        if ((sock_fd=socket(AF_INET, SOCK_STREAM, 0))==-1){
                printf("socket() error\n");
                exit(1);
        }
        setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseport, sizeof(int));
        //连接其他服务器并发出数据
        bzero(&server,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(PORT);
        server.sin_addr.s_addr = inet_addr(HOST);

        //使用本地指定端口建立TCP连接
        struct hostent *he;
        he = gethostbyname(LOCALHOST);
        bzero(&client,sizeof(client));
        client.sin_family = AF_INET;
        client.sin_port = htons(local_port);
        client.sin_addr = *((struct in_addr *)he->h_addr);;
        setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseport, sizeof(int));
        if (bind(sock_fd, (struct sockaddr *)&client, sizeof(struct sockaddr_in)) < 0){
                perror("bind error");
                exit(-1);
        }
        if (connect(sock_fd,(struct sockaddr *)&server, sizeof(struct sockaddr)) < 0){
                perror("connect error");
                exit(1);
        }

        struct sockaddr_in local;
        socklen_t local_len = sizeof(local);
        //获取TCP连接的本地IP端口信息
        getsockname(sock_fd, (struct sockaddr *)&local, &local_len);
        char local_ip[100];
        inet_ntop(AF_INET, &local.sin_addr, local_ip, sizeof(local_ip));
        printf("local host %s and port %d\n", local_ip, ntohs(local.sin_port));
        local_port = ntohs(local.sin_port);


        //功能一:绑定2012端口提供TCP服务
        pthread_t id;
        int ret = pthread_create(&id, NULL, (void *)serve_proc, (void *)local_port);
        if (ret!=0) {
                perror("create thread error");
                exit(-1);
        }

        int send_num, recv_num;
        char send_buf[100],recv_buf[100];

LBL:
        //功能二:使用2012端口充当客户端访问远程TCP服务器
        printf("Input MSG: ");
        scanf("%s",send_buf);
        send_num = send(sock_fd, send_buf, strlen(send_buf), 0);
        if (send_num < 0) {
                perror("send error");
                exit(1);
        }
        goto LBL;
}
主要使用端口复用,就让程序在监听2012端口作为TCP服务器的同时充当客户端使用2012端口去访问远程服务器的1987端口。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值