当前位置:   article > 正文

c语言实现简单tcp通信(多线程实现一个服务端处理多个客户端服务)_c实现 tcp新建连接数

c实现 tcp新建连接数

1、可下载源码(客户端 || 服务端通信)

tcp通信代码资源
在这里插入图片描述

2、说明

功能:tcp服务端与多个客户端进行通信(服务端通过多线程方式处理客户端服务),初始设置参数,解决服务端重启出现地址占用问题

编译:
make clean
make

执行:
(tcp服务端,系统中只能运行一个)
./server
在这里插入图片描述

(tcp客户端,可运行多个,打开另外的终端窗口执行)
./client
在这里插入图片描述

3、接口代码

tcp_api.h

/*************************************************
function:tcp 服务端和客户端总接口,多线程实现一个服务端处理多个客户端通信服务
author:zyh
date:2020.4
**************************************************/

#ifndef _TCP_CLIENT_AND_SERVER_H_
#define _TCP_CLIENT_AND_SERVER_H_


#ifdef __cplusplus
extern "C" {
#endif

int tcp_creat_socket(void);//创建socket(默认为堵塞模式)
int tcp_client_connect(int sockfd, char *server_ip, int server_port);//tcp客户端连接服务器
int tcp_send(int sockfd,  void *sendBuf,  int len);//tcp发送消息
int tcp_recv(int sockfd, void *recvBuf, int len);//tcp接收消息
int tcp_recv_nonblock(int sockfd,  void *recvBuf, int len, int timeval_sec, int timeval_usec);//tcp非堵塞接收消息
void tcp_close(int sockfd);//tcp关闭socket通信

//服务端多出来的部分
int tcp_server_bind_and_listen(int sockfd, char *server_ip, int server_port, int max_listen_num);//tcp服务器绑定端口、监听设置
int tcp_server_accept(int sockfd);//tcp等待客户端连接
int tcp_server_accept_nonblock(int sockfd, int timeval_sec, int timeval_usec);//tcp非阻塞等待客户端连接
void tcp_server_creat_pthread_process_client(int *new_sockfd, void* (*callBackFun)(void*));//服务端每接收到新的客户端连接,就创建新线程提供服务,外部需要重写处理消息的回调函数,参考void *tcp_server_callBackFun_demo(void *ptr)
void *tcp_server_callBackFun_demo(void *ptr);//callBackFun:处理客户端消息的回调函数,示例


#ifdef __cplusplus
}
#endif

#endif

  • 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

tcp_api.c

/*************************************************
function:tcp 服务端和客户端总接口,多线程实现一个服务端处理多个客户端通信服务
author:zyh
date:2020.4
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>   
#include <arpa/inet.h>//提供IP地址转换函数
#include <sys/types.h>//数据类型定义文件
#include <sys/socket.h>//提供socket函数及数结构
#include <netinet/in.h>//定义数据结构体sockaddr_in
#include <netinet/ip.h>
#include <pthread.h>
//#include <stdbool.h>
#include "tcp_api.h"


/**
函数功能:tcp创建socket通信
入参:无
出参:无
返回:成功:socket通信句柄,失败:-1
**/
int tcp_creat_socket(void)
{
	int sockfd = 0;
	//sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//TCP 传输协议
	//sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);//非阻塞模式
	sockfd = socket(AF_INET, SOCK_STREAM, 0);//默认堵塞模式
	if (0 > sockfd) {
		perror("socket");
		return -1;
	}
	
	//设置一下参数属性,防止服务端重启,出现地址占用问题
	int bReuseaddr = 1;//允许重用本机地址和端口, close socket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket
	if (0 > setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&bReuseaddr, sizeof(int))) {
		perror("setsockopt SO_REUSEADDR");
	}

#if 0//读缓冲区大小
	unsigned long snd_size = 0;/*发送缓冲区大小*/
	unsigned long rcv_size = 0;/*选项值长度*/
	socklen_t optlen;/*选项值长度*/ 
	optlen = sizeof(snd_size);//获得原始发送缓冲区大小
	getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &snd_size, &optlen);
	optlen = sizeof(rcv_size);
	getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen);
	printf("发送缓冲区原始大小为:%ld \n", snd_size);
	printf("接收缓冲区原始大小为:%ld \n", rcv_size);
#endif
	
#if 0//设置缓冲区大小
	// 接收缓冲区
	int nRecvBuf = 48*1024;//设置为48K
	if(0 > setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int))) {
		perror("setsockopt SO_RCVBUF");
	}
	
	//发送缓冲区
	int nSendBuf = 48*1024;//设置为48K
	if(0 > setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&nSendBuf, sizeof(int))) {
		perror("setsockopt SO_SNDBUF");
	}
#endif

#if 0
	//一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性
	int bBroadcast = 1;
	if(0 > setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&bBroadcast, sizeof(int))) {
		perror("setsockopt SO_BROADCAST");	
	}
#endif

	return sockfd;
}

/**
函数功能:tcp客户端连接服务器
入参:socket:socket通信句柄
入参:server_ip:服务器ip
入参:server_port:服务器端口(提供给客户端连接的端口)
出参:无
返回:成功:0, 失败:-1
**/
int tcp_client_connect(int sockfd, char *server_ip, int server_port)
{
	unsigned int server_addr = 0;
	struct sockaddr_in st_server_addr = {0};

	st_server_addr.sin_family = AF_INET;
	st_server_addr.sin_port = htons(server_port);//端口号,无符号短整型数值转换为网络字节序,即大端模式(big-endian)
	inet_pton(AF_INET, server_ip, &server_addr);//ip转换函数,主机字节序转化为网络字节序
	st_server_addr.sin_addr.s_addr = server_addr;
	
	if (0 > connect(sockfd, (struct sockaddr *)&st_server_addr, sizeof(st_server_addr))) {
		perror("connect");
		return -1;
	}
	
	return 0;
}

/**
函数功能:tcp发送消息
入参:sockfd:句柄
入参:sendBuf:发送的消息内容;
入参:len:发送的消息内容长度(字节)(如果使用strlen计算长度时请注意碰到0x00会截至)
出参:无
返回:成功:实际发送的字节数,通信中断:0,失败:-1
**/
int tcp_send(int sockfd,  void *sendBuf,  int len)
{
	int sendbytes = 0;

	if (0 > (sendbytes = send(sockfd, sendBuf, len,  MSG_DONTWAIT|MSG_NOSIGNAL))) {
		perror("send");
		return -1;
	}
	return sendbytes;
}

/**
函数功能:tcp接收消息
入参:sockfd:文件操作句柄
入参:recvBuf:接收的消息缓冲区(使用前后注意清空消息缓冲区,要不然存放消息会遗留上次接收的部分数据)
入参:len:缓冲区长度
出参:无
返回:成功:实际接收的字节数(其中:如果连接已中止,返回0), 失败:-1
**/
int tcp_recv(int sockfd, void *recvBuf, int len)
{
	int recvbytes = 0;

	if (0 > (recvbytes = recv(sockfd, recvBuf, len, 0)) ) {
		perror("recv");
		return -1;
	}
	
	return recvbytes;
}

/**
函数功能:tcp非堵塞接收消息
入参:sockfd:句柄
入参:recvBuf:接收的消息缓冲区(使用前后注意清空消息缓冲区,要不然存放消息会遗留上次接收的部分数据)
入参:len:缓冲区长度
入参:timeval_sec:超时时间(秒)
入参:timeval_usec:超时时间(微秒)
出参:无
返回:成功:实际接收的字节数(其中:如果连接已中止,返回0), 失败:-1,  超时:-2
**/
int tcp_recv_nonblock(int sockfd,  void *recvBuf, int len, int timeval_sec, int timeval_usec)
{
	fd_set readset;
	struct timeval timeout = {0, 0};
	int maxfd = 0;
	int recvbytes = 0;
	int ret = 0;
	
	timeout.tv_sec = timeval_sec;
	timeout.tv_usec = timeval_usec;
	FD_ZERO(&readset);           
	FD_SET(sockfd, &readset);         

	maxfd = sockfd + 1;

	ret = select(maxfd, &readset, NULL, NULL, &timeout); 
	if (0 >= ret) {
		return -2;
	} else {
		if (FD_ISSET(sockfd, &readset)) {
			if (0 > (recvbytes = recv(sockfd, recvBuf, len, MSG_DONTWAIT))) {
				perror("recv");
				return -1;
			}
		} else {
			return -1;
		}
	}
	
	return recvbytes;
}

/**
函数功能:tcp关闭sockfd通信句柄
入参:sockfd:socket通信句柄
出参:无
返回:无
**/
void tcp_close(int sockfd)
{
	//close(sockfd);
	if (sockfd > 0) {  //sockfd等于0时不能关,防止把文件句柄0关掉,影响系统,会导致scanf()函数输入不了
		close(sockfd);
	}
}


/*********************以下是服务端多出来的部分********************************************************************************************/
/**
函数功能:tcp服务器绑定端口、监听设置
入参:sockfd:socket通信句柄
入参:server_ip:服务器本地IP
入参:server_port:服务器本地端口(提供给客户端连接的端口)
入参:max_listen_num:最大监听客户端的数目
出参:无
返回:成功返回0, 失败返回-1
**/
int tcp_server_bind_and_listen(int sockfd, char *server_ip, int server_port, int max_listen_num)
{
	unsigned int server_addr = 0;
	struct sockaddr_in st_LocalAddr = {0}; //本地地址信息结构图,下面有具体的属性赋值
	
	st_LocalAddr.sin_family = AF_INET;  //该属性表示接收本机或其他机器传输
	st_LocalAddr.sin_port = htons(server_port); //端口号,无符号短整型数值转换为网络字节序,即大端模式(big-endian)
	inet_pton(AF_INET, server_ip, &server_addr);//ip转换函数,主机字节序转化为网络字节序
	st_LocalAddr.sin_addr.s_addr = server_addr;
	
	//绑定地址结构体和socket
	if(0 > bind(sockfd, (struct sockaddr *)&st_LocalAddr, sizeof(st_LocalAddr))) {
		perror("bind");
		return -1;
	}
 
	//开启监听 ,第二个参数是最大监听数
	if(0 > listen(sockfd, max_listen_num)) {
		perror("listen");
		return -1;
	}
	
	return 0;
}



/**
函数功能:tcp等待客户端连接
入参:sockfd:socket通信句柄;
出参:无
返回:成功:与客户端连接后的新句柄,失败:-1
**/
int tcp_server_accept(int sockfd)
{
	int new_sockfd = 0;//建立连接后的句柄

	struct sockaddr_in st_RemoteAddr = {0}; //对方地址信息
 	socklen_t socklen = 0;  
	
	//在这里阻塞直到接收到连接,参数分别是socket句柄,接收到的地址信息以及大小 
	new_sockfd = accept(sockfd, (struct sockaddr *)&st_RemoteAddr, &socklen);
	if(0 > new_sockfd) {
		perror("accept");
		return -1;
	}
	
	return new_sockfd;
}


/**
函数功能:tcp非阻塞等待客户端连接
入参:sockfd:socket通信句柄;
出参:无
返回:成功:与客户端连接后的新句柄,失败:-1  ,   超时:-2
**/
int tcp_server_accept_nonblock(int sockfd, int timeval_sec, int timeval_usec)
{
	int new_sockfd = 0;//建立连接后的句柄

	struct sockaddr_in st_RemoteAddr = {0}; //对方地址信息
 	socklen_t socklen = 0;  

	int flags = fcntl(sockfd, F_GETFL, 0);//设置socket为非阻塞
	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);


	fd_set readset;
	struct timeval timeout = {0, 0};
	int maxfd = 0;

	timeout.tv_sec = timeval_sec;
	timeout.tv_usec = timeval_usec;
	FD_ZERO(&readset);           
	FD_SET(sockfd, &readset);         
	maxfd = sockfd + 1;
	
	int ret = select(maxfd, &readset, NULL, NULL, &timeout); 
	if (0 >= ret) {
		return -2;//超时
	}
	if (0 == FD_ISSET(sockfd, &readset)) {
		return -1;
	}

	new_sockfd = accept(sockfd, (struct sockaddr *)&st_RemoteAddr, &socklen);
	if (0 > new_sockfd) {
		perror("accept");
		return -1;
	}
	
	return new_sockfd;
}



/**
函数功能:服务端每接收到新的客户端连接,就创建新线程提供服务
入参:new_sockfd:客户端连接上服务端后产生的新socket句柄
入参:callBackFun:处理客户端消息的回调函数
出参:无
返回:无
**/
void tcp_server_creat_pthread_process_client(int *new_sockfd, void* (*callBackFun)(void*))
{
	pthread_t thread_id;
	//int ret = 0;
	
	pthread_create(&thread_id, NULL, callBackFun, (void *)new_sockfd);
	pthread_detach(thread_id);//将线程分离, 线程结束后自动释放线程资源,后续不需要使用pthread_join()进行回收
}

//callBackFun:处理客户端消息的回调函数,示例
void *tcp_server_callBackFun_demo(void *ptr)
{
	//int *new_sockfd = (int *)ptr;//错误,不能直接使用地址,防止外部地址数值改变
	int new_sockfd = *(int *)ptr;
	printf("新建线程处理客户端服务(new_sockfd=%d)\n", new_sockfd);
	
	char recv_buff[1024] = {0};
	int recv_len = 0;
	
	char *str = NULL;
	
	while (1) {
		memset(recv_buff, 0, sizeof(recv_buff));
		
		recv_len = tcp_recv(new_sockfd, recv_buff, sizeof(recv_buff));//堵塞接收消息
		if(0 > recv_len) {
			printf("接收客户端消息失败(new_sockfd=%d)!\n", new_sockfd);
			break;
		} else if(0 == recv_len) {
			printf("客户端断开连接(new_sockfd=%d)\n", new_sockfd);
			break;
		} else {
			printf("接收客户端消息(new_sockfd=%d):%s\n", new_sockfd, recv_buff);
			str = (char *)"服务端已收到";
			tcp_send(new_sockfd, str, strlen(str));
		}
		//usleep(1*1000);
	}
	
	tcp_close(new_sockfd);
	
	printf("退出线程服务(new_sockfd=%d)\n", new_sockfd);
	return NULL;
}
  • 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
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360

4、客户端通信main_client_demo.c

/*************************************************
Function:tcp 客户端进程,服务器中可运行多个
author:zyh
date:2020.4
**************************************************/
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include"tcp_api.h"

int sockfd = -1;//客户端socket通信句柄
int tcp_client_connectflag = 0;//客户端socket通信连接标志

//开启一个接收消息的线程
void *fun_client_rcv(void *ptr)
{
	char recvBuf[1024] = {0};
	int recvBytes = 0;
	
	while (1) {
		if (1 == tcp_client_connectflag) {
			//堵塞接收
			memset(recvBuf, 0, sizeof(recvBuf));//清空
			recvBytes = tcp_recv(sockfd, recvBuf, sizeof(recvBuf));//堵塞接收
			if (0 > recvBytes) {//接收失败
				printf("接收失败\n");
				tcp_client_connectflag = 0;
			} else if (0 == recvBytes) {//断开了连接
				printf("已断开连接\n");
				tcp_client_connectflag = 0;
			} else {
				printf("接收到消息:%s\n", recvBuf);
			}
		} else {
			sleep(1);
		}
	}
	
	return NULL;
}

//开启一个发送消息的线程
void *fun_client_send(void *ptr)
{
	char msg_buf[1024] = {0};
	
	while (1) {
		if (1 == tcp_client_connectflag) {//连接成功
			printf("\n请输入要发送的消息:\n");
			scanf("%s", msg_buf);
			printf("正在发送\n");
			if (0 > tcp_send(sockfd, msg_buf, strlen(msg_buf))) {//如果含有0x00不能用strlen
				printf("发送失败...!\n");
				tcp_client_connectflag = 0;
			} else {
				printf("发送成功\n");
			}
			sleep(1);
		} else {
			sleep(1);
		}
	}
	
	return NULL;
}

int main(int argc, char *argv[])
{
	char server_ip[16] = {0};//服务器IP
	int server_port = 0;//服务器端口
	int ret = 0;
	
	pthread_t thread_client_rcv, thread_client_send;

	//创建一个接收消息线程
	ret = pthread_create(&thread_client_rcv, NULL, fun_client_rcv, NULL);
	if (ret < 0) {
		printf("creat thread_client_rcv is fail!\n");
		return -1;
	}
	
	ret = pthread_create(&thread_client_send, NULL, fun_client_send, NULL);
	if (ret < 0) {
		printf("creat fun_client_send is fail!\n");
		return -1;
	}
		
	printf("请输入服务器ip:\n");
	scanf("%s", server_ip);
	
	printf("请输入服务器端口:\n");
	scanf("%d", &server_port);

	while (1) {
		if (0 == tcp_client_connectflag) {//未连接就不断中断重连
	
			if (sockfd > 0) {  //sockfd等于0时不能关,防止把文件句柄0关掉,导致scanf()函数输入不了
				tcp_close(sockfd);
			}
			
			sockfd = tcp_creat_socket();//创建socket
			if (0 > sockfd) {
				printf("socket创建失败...!\n");
				sleep(2);
				continue;
			}
			
			printf("请求连接...\n");
			if (0 > tcp_client_connect(sockfd, server_ip, server_port)) {
				printf("连接失败...重连中...\n");
				sleep(2);
				continue;
			} else {
				tcp_client_connectflag = 1;
				printf("连接成功!\n");
			}	
		} else {
			sleep(1);
		}
	}
	
	tcp_close(sockfd);
	pthread_join(thread_client_rcv, NULL);
	pthread_join(thread_client_send, NULL);
	return 0;
}
  • 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

5、服务端通信main_server_demo.c

/*************************************************
Function:tcp 服务端进程,服务器中运行只一个
author:zyh
date:2020.4
**************************************************/
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include"tcp_api.h"

void *tcp_server_callBackFun(void *ptr)
{
	//int new_sockfd = (int *)ptr;//错误,不能直接使用地址,防止外部地址数值改变
	int new_sockfd = *(int *)ptr;
	
	printf("开启线程服务处理客户端(new_sockfd=%d)\n", new_sockfd);
	
	char recv_buff[1024*30] = {0};
	int recv_len = 0;
	
	char *str = NULL;
	
	while (1) {
		memset(recv_buff, 0, sizeof(recv_buff));
		
		//recv_len = tcp_recv(new_sockfd, recv_buff, sizeof(recv_buff));//堵塞接收消息
		recv_len = tcp_recv_nonblock(new_sockfd, recv_buff, sizeof(recv_buff), 1, 0);
		if ((-1) == recv_len) {
			printf("接收客户端消息失败(new_sockfd=%d)!\n", new_sockfd);
			break;
		} else if ((-2) == recv_len) {
			//printf("接收客户端消息超时(new_sockfd=%d)!\n", new_sockfd);
			continue;
		} else if(0 == recv_len) {
			printf("客户端断开连接(new_sockfd=%d)\n", new_sockfd);
			break;
		} else {
			printf("收到客户端消息(new_sockfd=%d):%s\n\n", new_sockfd, recv_buff);
			//str = (char *)"服务端已收到";
			//tcp_send(new_sockfd, str, strlen(str));
		}
		//usleep(1*1000);
	}
	
	tcp_close(new_sockfd);
	
	printf("退出线程服务(new_sockfd=%d)\n", new_sockfd);
	return NULL;
}



int main(int argc, char *argv[])
{
	int ret = 0;

	int sockfd = -1;
	sockfd = tcp_creat_socket();//创建socket
	if (0 > sockfd) {
		printf("socket创建失败...!\n");
		return -1;
	}
	
	int port = 2022;
	char *ip = (char *)"0.0.0.0";
	
	ret = tcp_server_bind_and_listen(sockfd, ip, port, 1024);
	if (0 > ret) {
		printf("bind_and_listen失败...!\n");
		tcp_close(sockfd);
		return -1;
	}
	printf("服务端ip=localHost, 端口=%d\n", port);
	
	int new_sockfd = -1;
	while (1) {
		if (0 > (new_sockfd = tcp_server_accept(sockfd))) {//堵塞直到客户端连接
		//if (0 > (new_sockfd = tcp_server_accept_nonblock(sockfd, 1, 0))) {//非堵塞等待客户端连接
			printf("等待连接...!\n");
			continue;
		} else {
			printf("\n有客户端连接成功! new_sockfd=%d\n", new_sockfd);
			tcp_server_creat_pthread_process_client(&new_sockfd, tcp_server_callBackFun);//服务端每接收到新的客户端连接,就创建新线程提供服务
		}
	}
	
	tcp_close(sockfd);

	return 0;
}
  • 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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/144069
推荐阅读
相关标签
  

闽ICP备14008679号