本文主要解决的需求是,通过一个服务端控制多个设备。多个设备中分为一主多从。服务端与主机直接通信,主机拆分转发消息到从机,再从从机中接收数据,并整合数据发送给服务端。 不难看出在该需求中,主机既作为tcp的客户端与服务端通信,又作为服务端与多个从机通信。因此涉及到tcp的多线程及同一个端口既作服务端又作客户端。
我用windows系统的通信助手作为服务端。以下为通信助手的界面:
主机和从机的代码在ubuntu虚拟机中执行。虚拟机网络选择桥接模式。下面是我的主机代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#define PORT 1987
#define HOST "192.168.0.83"
#define LOCALPORT 2012
#define LOCALHOST "192.168.0.120"
typedef struct arg {
int confd;
struct sockaddr_in client;
} arg_t;
void *threadFun(void *argv)
{
char recv_buf[1024] = "";
arg_t *arg = (arg_t*)argv;
int sockfd = arg->confd;
struct sockaddr_in client;
memcpy(&client, &arg->client, sizeof(struct sockaddr_in));
int buflen = 0;
while(1)
{
buflen = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
if(buflen > 0) {
printf("%s:%d recv_buf: %s\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port),recv_buf);
}
}
}
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");
return;
}
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;
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");
return;
}
if (listen(sock_fd,5) < 0) {
perror("listen error");
return;
}
char recv_buf[100],send_buf[100];
int conn_fd;
int client_size = sizeof(struct sockaddr_in);
int i = 0;
while(1){
conn_fd = accept(sock_fd, (struct sockaddr *)&client, &client_size);
if (conn_fd > 0){
pthread_t thread;
arg_t arg1 = {0};
arg1.confd = conn_fd;
memcpy(&arg1.client, &client, sizeof(struct sockaddr_in));
pthread_create(&thread, NULL, (void*)threadFun, (void*)&arg1);
}
}
}
void thread2(void* arg)
{
int *sock_fd = (int*)arg;
char recv_buf[1024] = "";
int buflen = 0;
while(1)
{
buflen = recv(*sock_fd, recv_buf, sizeof(recv_buf), 0);
if(buflen > 0) {
printf("recv_buf: %s\n",recv_buf);
}
}
}
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");
return 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);
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_list[0]);;
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");
return -1;
}
if (connect(sock_fd,(struct sockaddr *)&server, sizeof(struct sockaddr)) < 0){
perror("connect error");
return 1;
}
struct sockaddr_in local;
socklen_t local_len = sizeof(local);
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);
pthread_t thread;
pthread_create(&thread, NULL, (void*)thread2, (void*)&sock_fd);
serve_proc(LOCALPORT);
}
以下是从机代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
int main()
{
int sockfd;
int n;
struct sockaddr_in servaddr;
char sendbuf[] = "hello world";
sockfd = socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
if(sockfd == -1) {
printf("init failed\n");
} else {
printf("init successfully\n");
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.0.120");
servaddr.sin_port = htons(2012);
n = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
int buflen = 0;
if(n == 0){
while(1)
{
buflen = send(sockfd,sendbuf, strlen(sendbuf)+1, 0);
if(buflen > 0) {
printf("send successfully\n");
}
sleep(5);
}
}
close(sockfd);
return 0;
}
下面是运行结果 感觉写的很清楚了。欢迎大佬指点。
|