socket基于tcp的服务端与客户端实例

socket基于tcp的服务端与客户端实例

先运行服务端再运行客户端,服务端收到客户端下属的开始指令后,两边同时创建线程,服务端收到客户端下属的停止指令后,两边同时停止线程

server.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#include <fcntl.h>              // Flags for open()
#include <sys/stat.h>           // Open() system call
#include <sys/types.h>          // Types for open()
#include <unistd.h>             // Close() system call
#include <string.h>             // Memory setting and copying
#include <getopt.h>             // Option parsing
#include <errno.h>              // Error codes
#include<sys/socket.h>
#include<netinet/in.h>
#include <pthread.h>


#define DEFAULT_PORT 4000
#define MAXLINE 4096
#define socket_send_size 4096

int    socket_fd, connect_fd;
int    flag1;

// 全局变量
pthread_t worker_thread = 0; // 工作线程 ID
volatile int thread_running = 0; // 线程运行状态
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁

int flag1;
int socket_fd, connect_fd;

void cleanup_handler() {	

}

void *receive_file(void *arg) {
	printf("enter therad\n");	

	pthread_cleanup_push(cleanup_handler, NULL);

    int i = 0, rc = 0;
    unsigned char send_buffer[socket_send_size] = {0};
    memset(send_buffer, 0, socket_send_size);
    
	while (flag1 == 1) {
#if 1
		for (i = 0; i < 4; i++) {
			if (flag1 != 1) break;
		}
		send(connect_fd, &send_buffer[0], socket_send_size, 0);
#endif
	}
	pthread_cleanup_pop(0);
	pthread_exit(NULL);
}

void create_thread() {
    pthread_mutex_lock(&mutex);
    if (!thread_running) {        

		int ret = pthread_create(&worker_thread, NULL, &receive_file, NULL);
		if (ret != 0) {
			perror("pthread_create");			
			exit(EXIT_FAILURE);
		}

        thread_running = 1;
        printf("Main: Created thread\n");
    } else {
        printf("Main: Thread is already running\n");
    }
    pthread_mutex_unlock(&mutex);
}

// 销毁线程
void destroy_thread() {
    pthread_mutex_lock(&mutex);
    if (thread_running) {
        printf("Main: Stopping thread...\n");
        int ret = pthread_cancel(worker_thread);
        if (ret != 0) {
            perror("pthread_cancel");
            exit(EXIT_FAILURE);
        }

        // 等待线程退出并回收资源
        ret = pthread_join(worker_thread, NULL);
        if (ret != 0) {
            perror("pthread_join");
            exit(EXIT_FAILURE);
        }

        thread_running = 0;
        printf("Main: Thread has exited.\n");
    } else {
        printf("Main: No thread is running\n");
    }
    pthread_mutex_unlock(&mutex);
}

// 主函数


/*----------------------------------------------------------------------------
 * Main
 *----------------------------------------------------------------------------*/

int main(void) {		
	// Socket相关变量
    struct sockaddr_in     servaddr;
	unsigned char    buff[MAXLINE];
	int     n;

    //初始化Socket
	if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
		printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
		exit(0);
	}
	// 解决 Address already in use 问题
    int opt = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	//初始化
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
	servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT

	//将本地地址绑定到所创建的套接字上
	if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
		printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
		exit(0);
	}
	//开始监听是否有客户端连接
	if( listen(socket_fd, 2) == -1) {
		printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
		exit(0);
	}
	printf("======waiting for client's request======\n");
	
	flag1 = 0;

	printf("start:\nFA 00 00 08 00 00 00 01\n");
	printf("stop:\nFA 00 00 08 00 00 00 02\n");
	while (1) {
		if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1) {
			printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
			usleep(10);
			continue;
		}
		printf("mark-1\n");
		while (1) {
			//接受客户端传过来的数据
			n = recv(connect_fd, buff, MAXLINE, 0);
			usleep(100);
			printf("mark-2\n");
			if(n > 0) {
				// 判断是开始还是停止
				if (buff[0] == 0xFA && buff[7] == 0x01) {
					// 开始
					printf("start\n");
					//sleep(1200); //测试长时间不执行操作,网口是否仍正常工作
					flag1 = 1;
					// 复位					
					create_thread();
					system("date");
				}
				else if (buff[0] == 0xFA && buff[7] == 0x02) {
					flag1 = 2;
					// 停止					
					destroy_thread();
					system("date");
				} 
			} else if (n < 0) {
				usleep(100);
				continue;
			} else {
				close(connect_fd);
				printf("mark-3\n");
				usleep(100);
				break;
			}
		}
		usleep(10);
	}
    close(connect_fd);
    close(socket_fd);
    return 0;
}

client.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

#define DEFAULT_PORT 4000
#define MAXLINE 4096

// 全局变量
pthread_t worker_thread = 0;          // 工作线程 ID
volatile int thread_running = 0;      // 线程运行状态
volatile int thread_should_exit = 0;  // 线程退出标志
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 互斥锁

// 线程清理函数
void cleanup_handler(void *arg) {
    printf("Thread: Cleaning up resources...\n");
}

// 工作线程函数
void *receive_file(void *arg) {
    printf("Thread: Entered thread\n");

    // 注册清理函数
    pthread_cleanup_push(cleanup_handler, NULL);

    while (!thread_should_exit) {
        // 模拟工作
        printf("Thread: Working...\n");
        sleep(1);
    }

    // 清理
    pthread_cleanup_pop(1);
    printf("Thread: Exiting...\n");
    return NULL;
}

// 创建线程
void create_thread() {
    pthread_mutex_lock(&mutex);
    if (!thread_running) {
        thread_should_exit = 0;  // 重置退出标志
        int ret = pthread_create(&worker_thread, NULL, receive_file, NULL);
        if (ret != 0) {
            perror("pthread_create");
            exit(EXIT_FAILURE);
        }
        thread_running = 1;
        printf("Main: Created thread\n");
    } else {
        printf("Main: Thread is already running\n");
    }
    pthread_mutex_unlock(&mutex);
}

// 销毁线程
void destroy_thread() {
    pthread_mutex_lock(&mutex);
    if (thread_running) {
        printf("Main: Stopping thread...\n");
        thread_should_exit = 1;  // 设置退出标志

        // 等待线程退出并回收资源
        int ret = pthread_join(worker_thread, NULL);
        if (ret != 0) {
            perror("pthread_join");
            exit(EXIT_FAILURE);
        }

        thread_running = 0;
        printf("Main: Thread has exited.\n");
    } else {
        printf("Main: No thread is running\n");
    }
    pthread_mutex_unlock(&mutex);
}

// 解析 16 进制输入
int parse_hex_input(const char *input, unsigned char *output, size_t output_size) {
    char *endptr;
    for (size_t i = 0; i < output_size; i++) {
        output[i] = (unsigned char)strtol(input + 2 * i, &endptr, 16);
        if (endptr != input + 2 * (i + 1)) {
            return -1;  // 非法输入
        }
    }
    return 0;
}

int main(int argc, char *argv[]) {
	int i = 0;
	int input = 0;
    int sockfd;
    struct sockaddr_in servaddr;

    // 检查命令行参数
    if (argc != 2) {
        printf("Usage: %s <ipaddress>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 创建 Socket
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("Create socket error: %s (errno: %d)\n", strerror(errno), errno);
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(DEFAULT_PORT);
    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
        printf("inet_pton error for %s\n", argv[1]);
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 连接到服务器
    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        printf("Connect error: %s (errno: %d)\n", strerror(errno), errno);
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("Connected to server at %s:%d\n", argv[1], DEFAULT_PORT);
	printf("start:\nFA 00 00 08 00 00 00 01\n");
	printf("stop:\nFA 00 00 08 00 00 00 02\n");

    // 主循环
    while (1) {
        unsigned char input_buf[8] = {0};
        char input_str[17];  // 8 个 16 进制数,每个占 2 字符,加上结束符

        for (i = 0; i < 8; i++) {
			scanf("%x", &input);
			input_buf[i] = input;
		}

        // 打印输入
        printf("Input: ");
        for (int i = 0; i < 8; i++) {
            printf("%02X ", input_buf[i]);
        }
        printf("\n");

        // 根据输入启动或停止线程
        if (input_buf[0] == 0xFA && input_buf[7] == 0x01) {
            create_thread();
			send(sockfd, &input_buf[0], sizeof(input_buf), 0);
        } else if (input_buf[0] == 0xFA && input_buf[7] == 0x02) {
            destroy_thread();
			send(sockfd, &input_buf[0], sizeof(input_buf), 0);
        }
    }

    // 清理资源
    destroy_thread();  // 确保线程退出
    pthread_mutex_destroy(&mutex);
    close(sockfd);

    return 0;
}

运行方式

server端

1
./server

显示结果并等待客户端连接

1
2
3
4
5
======waiting for client's request======
start:
FA 00 00 08 00 00 00 01
stop:
FA 00 00 08 00 00 00 02

client端

运行客户端后下发指令

start: FA 00 00 08 00 00 00 01 stop: FA 00 00 08 00 00 00 02

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ ./client 127.0.0.1
Connected to server at 127.0.0.1:4000
start:
FA 00 00 08 00 00 00 01
stop:
FA 00 00 08 00 00 00 02
FA 00 00 08 00 00 00 01
Input: FA 00 00 08 00 00 00 01
Main: Created thread
Thread: Entered thread
Thread: Working...
Thread: Working...
Thread: Working...
Thread: Working...
FA 00 00 08 00 00 00 02Thread: Working...

Input: FA 00 00 08 00 00 00 02
Main: Stopping thread...
Thread: Cleaning up resources...
Thread: Exiting...
Main: Thread has exited.
FA 00 00 08 00 00 00 01
Input: FA 00 00 08 00 00 00 01
Main: Created thread
Thread: Entered thread
Thread: Working...
Thread: Working...
Thread: Working...
Thread: Working...
FA 00 00 08 00 00 00 02Thread: Working...

Input: FA 00 00 08 00 00 00 02
Main: Stopping thread...
Thread: Cleaning up resources...
Thread: Exiting...
Main: Thread has exited.

此时服务端收到客户端下发的指令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ ./server
======waiting for client's request======
start:
FA 00 00 08 00 00 00 01
stop:
FA 00 00 08 00 00 00 02
mark-1
mark-2
start
Main: Created thread
enter therad
2025年03月20日 17:44:57
mark-2
Main: Stopping thread...
Main: Thread has exited.
2025年03月20日 17:45:02
mark-2
start
Main: Created thread
enter therad
2025年03月20日 17:45:10
mark-2
Main: Stopping thread...
Main: Thread has exited.
2025年03月20日 17:45:16