下面的代码主要实现两个功能:
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端口。