TCP通信—client与server

    TCP

        client -> 1.初始化套接字 -> 2.连接 -> 数据收发

        server -> 1.初始化套接字 -> 2.绑定 -> 3.监听 -> 4.接收客户端连接 -> 数据收发

client:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

// 函数声明
void *ThreadRecvData(void *);
char *GetTimeHMS();

// 主线程
int main(int argc, char **argv){
	
	int sockfd;							// 存储套接字
	pthread_t pt;
	unsigned short dft_port = 60000;
	struct sockaddr_in server_info;		// 存储服务端协议地址信息
	char buffer[1024] = {0};
	char *server_ip;

	if( argc < 2 ){
		fprintf(stderr, "<usage> : %s [IPv4] [port]\n" \
						"          Port default value is 60000 if you don't specify.\n", argv[0]);
		return -1;
	}
	server_ip = argv[1];
	if( argv[2] ){	// 如果制定了第二个参数
		dft_port = atoi(argv[2]);
	}

	/* 1. 初始化客户端套接字 */
	if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){
		perror("socket");
		return -1;
	}

	/* 2. 连接 */
	memset(&server_info, 0x00, sizeof(server_info));		// 清空协议地址结构
	server_info.sin_family      = AF_INET;					// 协议族
	server_info.sin_port        = htons(dft_port);			// 端口号
	server_info.sin_addr.s_addr = inet_addr(server_ip);		// IPv4地址
	
	if( -1 == connect(sockfd, (const struct sockaddr *)&server_info, sizeof(server_info)) ){
		perror("connect");
		return -1;
	}else{
		system("clear");
		printf("Connect successed\n");
	}

	// 创建线程用来接收数据
	if( pthread_create(&pt, NULL, ThreadRecvData, &sockfd) ){
		perror("connect");
		return -1;
	}

	// 发送数据
	while(1){
		fgets(buffer, sizeof(buffer), stdin);
		if(-1 == send(sockfd, buffer, strlen(buffer), 0) ){
			perror("send");
			break;
		}
	}

	/* 4. 关闭套接字 退出进程 */
	close(sockfd);

	return 0;
}

// 接收数据 - 线程
void *ThreadRecvData(void *arg){
	int  sockfd = *(int *)arg;		// 获取客户端的套接字
	char buffer[1024] = {0};
	ssize_t recvlen;
	
	while(1){
		memset(buffer, 0x00, sizeof(buffer));
		recvlen = recv(sockfd, buffer, sizeof(buffer), 0);
		if( !recvlen ){ break; }	// 连接被服务端关闭
		else if( -1 == recvlen ){
			perror("recv");
			close(sockfd);
			exit(-1);
		}
		printf("[%s]\n\t%s\n", GetTimeHMS(), buffer);
	}
	printf(
"Connection closed by foreign host.\n");
	close(sockfd);
	exit(0);
}

// 获取系统时间
char *GetTimeHMS(){
	static char buffer[64] = {0};
    time_t timep;
    struct tm *p = NULL;
    timep = time(NULL);    	// 获取时间戳
    if(NULL == (p = localtime(&timep)) ){
            perror("localtime");
            return NULL;
    }	// 解析时间数据并组装
    sprintf(buffer, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec);
    return buffer;
}


/*
================================================================================================

	int socket(int domain, int type, int protocol);
	函数功能 : 初始化套接字
	函数参数 : domain       - 协议族
			   type     - 套接字类型 SOCK_STREAM / SOCK_DGRAM
			   protocol - 如果已经通过参数domain/type指定了套接字的使用方式 则该参数写0
	返 回 值 : 成功返回初始化好的新套接字, 失败返回-1
 
================================================================================================

	int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
	函数功能 : 连接到目标服务端
	函数参数 : sockfd       - 初始化好的客户端套接字
			   addr     - 指针, 指向的内存中的数据有服务端使用的协议族/IP地址/端口号
			   addrlen  - 长度(字节), 存储目标协议地址信息结构的大小


	in_addr_t inet_addr(const char *cp);
	函数功能 : 将cp指向的字符串内容(点分十进制形式的IP地址)转换位网络字节序无符号32位整型值

================================================================================================
*/

server:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

void *ThreadHandler(void *arg);

int main(){

	int sockfd;		// 仅用来监听
	struct sockaddr_in server_info;

	if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)) ){
		perror("socket");
		return -1;
	}

	memset(&server_info, 0x00, sizeof(server_info));
	server_info.sin_family      = AF_INET;
	server_info.sin_port        = htons(50000);
	server_info.sin_addr.s_addr = INADDR_ANY;

	if(-1 == bind(sockfd, (const struct sockaddr *)&server_info, sizeof(server_info)) ){
		perror("bind");
		return -1;
	}

	if(-1 == listen(sockfd, 1024)){
		perror("listen");
		return -1;
	}

	struct sockaddr_in client_info;
	socklen_t info_size = sizeof(client_info);
	int client_fd;
	pthread_t pt;

	while(1){
		// accept会阻塞程序运行 直到有客户端发起连接请求
		if(-1 == (client_fd = accept(sockfd, NULL, NULL)) ){
			perror("accept");
			return -1;
		}
		pthread_create(&pt , NULL, ThreadHandler, &client_fd);
	}

	
	close(sockfd);

	return 0;
}

void *ThreadHandler(void *arg){
	int client_fd = *(int *)arg;
	char buffer[1024];
	printf("New client %d connected.\n", client_fd);
	while(1){
		if( !recv(client_fd, buffer, sizeof(buffer), 0) ){
			close(client_fd);
			pthread_exit(NULL);
		}
	}
}
	

/*
	int bind  (int sockfd, const struct sockaddr *addr, socklen_t addrlen);

	int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	int accept     (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	接收一个客户端的连接
		sockfd - 监听套机字
		addr - 指针,指向的内存用来存储连接上来的客户端的协议地址数据
		addrlen - 指针,指向的内存中的数据用来描述协议地址结构的大小
	accept函数成功将会返回一个新套接字,这个套接字用来和刚刚连接上来的客户端进行通信

*/

TCP是一种面向连接的协议,用于在不同的计算机之间进行可靠的数据传输。在TCP中,服务器和客户端都是通过套接字(socket)来进行通信的。 TCP服务器的基本流程是: 1. 创建服务器套接字,指定服务器的IP地址和端口号。 2. 绑定服务器套接字到指定的IP地址和端口号。 3. 监听来自客户端的连接请求。 4. 接受来自客户端的连接请求,并创建一个新的套接字用于和客户端进行通信。 5. 和客户端进行数据通信,直到数据传输完毕或者客户端关闭连接。 6. 关闭和客户端的套接字,并回到第4步,等待下一个客户端的连接请求。 TCP客户端的基本流程是: 1. 创建客户端套接字,指定服务器的IP地址和端口号。 2. 连接到服务器。 3. 和服务器进行数据通信,直到数据传输完毕或者服务器关闭连接。 4. 关闭客户端套接字。 下面是一个简单的示例代码,演示了如何使用Python的socket模块实现TCP服务器和客户端通信TCP服务器代码: ```python import socket # 创建服务器套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定服务器套接字到指定的IP地址和端口号 server_socket.bind(('127.0.0.1', 8888)) # 监听来自客户端的连接请求 server_socket.listen(5) while True: # 接受来自客户端的连接请求,并创建一个新的套接字用于和客户端进行通信 client_socket, client_address = server_socket.accept() print(f"连接已建立,客户端地址为{client_address}") # 和客户端进行数据通信,直到数据传输完毕或者客户端关闭连接 while True: data = client_socket.recv(1024) if not data: break print(f"收到客户端的数据:{data.decode('utf-8')}") client_socket.sendall(data) # 关闭和客户端的套接字 client_socket.close() ``` TCP客户端代码: ```python import socket # 创建客户端套接字 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接到服务器 client_socket.connect(('127.0.0.1', 8888)) # 和服务器进行数据通信,直到数据传输完毕或者服务器关闭连接 while True: data = input("请输入要发送的数据:") if not data: break client_socket.sendall(data.encode('utf-8')) data = client_socket.recv(1024) print(f"收到服务器的数据:{data.decode('utf-8')}") # 关闭客户端套接字 client_socket.close() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值