Linux下的socket通信的简单实现 修改版

本文介绍了一个简单的聊天服务器和客户端的实现方法,使用多线程来处理客户端的接收和发送操作,支持同时与多个客户端进行交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我2014年2月份写的代码 code 的基础上,我进行了修改和增减功能。主要体现在下面几个方便:

  1.  main函数不再是从程序开头写到结尾,而是分成了一个个较短的、功能明确的函数。
  2.  增加多线程支持
  3. 增删注释,换成中文注释

服务器端代码:

/*
 * Filename: server.c 
 * version 1.1
 * Author :	Bruce Zhang
 * Last edit time: Oct 16th, 2014
 */

#include <netinet/in.h>   // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>   // for socket
#include <stdio.h>        // for printf
#include <errno.h>        // for errno
#include <stdlib.h>       // for exit
#include <string.h>       // for memset

#include <pthread.h>	  // for pthread

#define SERVER_PORT   6666 
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024


struct sockaddr_in server_addr; 	// 设置一个服务器端的socket地址结构server_addr,代表服务器internet地址, 端口
int server_socket_fd;  			// 服务器端的文件描述符
char buffer_receive[BUFFER_SIZE]; 	// 定义接收字符的缓冲数组
char buffer_send[BUFFER_SIZE]; 		// 定义发送字符的缓冲数组

int fd_temp; // 文件描述符

pthread_t thread_send_fd;		// 用于发送字符串的线程
pthread_t thread_receive_fd;		// 用于接收字符串的线程

void init_server_socket() {
	
	// buffer 清零
	memset(buffer_receive, 0, BUFFER_SIZE);
	memset(buffer_send, 0, BUFFER_SIZE);

	// 初始化 server_addr,即服务器端的socket地址
	memset(&server_addr, 0, sizeof(server_addr)); 
    	server_addr.sin_family = AF_INET; 	// sin_family指代协议族,在socket编程中只能是AF_INET			
    	server_addr.sin_addr.s_addr = htons(INADDR_ANY); // sin_addr也是个结构体,里面存放着IP地址
    	server_addr.sin_port = htons(SERVER_PORT);	// sin_port指的是端口号,主机字节序转化成网络字节序
}

void check_fd(int fd, char *info) {
	if(fd == -1) {
		printf(" %s failed...\n", info);
		printf(" (errno: %d) %s\n", errno, strerror(errno));
		exit(1);
	}
}

// 接收数据 receive
void *thread_receive(void *arg) {
	int new_socket_fd = *(int *)arg;
	while(1) {
		memset(buffer_receive, 0, BUFFER_SIZE);
		int buflen = recv(new_socket_fd, buffer_receive, BUFFER_SIZE, 0);
		check_fd(buflen, "receive");
		if (buflen == 0)
			continue;
		printf("\nclient:    %s", buffer_receive);	
		printf("\nI say:    ");   
		// bye 结束会话
		// trim(buffer_receive);
		if(strcmp(buffer_receive, "bye") == 0) {
			close(new_socket_fd); break;
		}
		sleep(1);	
	}	
}

// 读取并发送数据 send
void *thread_send(void *arg) {
	int new_socket_fd = *(int *)arg;
	while(1) {		  	
		memset(buffer_send, 0, BUFFER_SIZE);
		fgets(buffer_send, BUFFER_SIZE, stdin);       	
		int buflen = send(new_socket_fd, buffer_send, sizeof(buffer_send), 0);
		check_fd(buflen, "send"); 
	}		
}

void begin_conversation(int new_socket_fd) {

	printf(" conversation detected\n\n");
	int err1 = pthread_create(&thread_send_fd, NULL, thread_send, &new_socket_fd);
	if(err1 != 0) 
		printf("%s\n",strerror(err1)); 
	int err2 = pthread_create(&thread_receive_fd, NULL, thread_receive, &new_socket_fd);
	if(err2 != 0) 
		printf("%s\n",strerror(err2)); 
}

int main(int argc, char const *argv[])
{
	// 1. 初始化socket
	init_server_socket();

	// 2. 创建socket,原型是 int socket(int domain, int type, int protocol);
	server_socket_fd = socket(AF_INET, SOCK_STREAM, 0); 
	check_fd(server_socket_fd, "create server socket");
		
	// 3. 绑定(bind) server_socket_fd 和 server_addr 函数原型为: int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
	fd_temp = bind(server_socket_fd,(struct sockaddr*)&server_addr, sizeof(server_addr) );
   	check_fd(fd_temp, "bind");

	// 4. 打开监听,原型是 int listen(int sockfd, int backlog); 第二个参数是等待队列的大小
	fd_temp = listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE);
	check_fd(fd_temp, "begin listening");
	
	printf("welcome to chit-chat~ the server is listening for a guest \n");

	// 5. 开始接收(accept)和 收发数据(receive && send)
   	while(1) {
		struct sockaddr_in client_addr; 	// 此变量用来存放链接的客户端socket地址,和server_addr比较	
		socklen_t length = sizeof(client_addr);

		// 如果没有连接请求,就等待到有连接请求--这是accept函数的特性
		// accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
		int new_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &length); 
		check_fd(new_socket_fd, "new socket accepted");

		// 开始会话
		begin_conversation(new_socket_fd);
	}
	close(thread_send_fd);
	close(thread_receive_fd);
	close(server_socket_fd);
	return 0;
}	

客户端代码:

/*
 * Filename: client.c 
 * version 1.1
 * Author :	Bruce Zhang
 * Last edit time: Oct 16th, 2014
 */

#include <netinet/in.h>   // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>   // for socket
#include <stdio.h>        // for printf
#include <errno.h>        // for errno
#include <stdlib.h>       // for exit
#include <string.h>       // for memset

#include <pthread.h>	  // for pthread

#define SERVER_PORT  6666 
#define BUFFER_SIZE  1024

int client_socket_fd;
struct sockaddr_in server_address;
socklen_t server_addr_length;
char buffer_receive[BUFFER_SIZE]; 
char buffer_send[BUFFER_SIZE];

int fd_temp;

pthread_t thread_send_fd;		// 用于发送字符串的线程
pthread_t thread_receive_fd;		// 用于接收字符串的线程

void check_fd(int fd, char *info) {
	if(fd == -1) {
		printf("%s failed...\n", info);
		printf("(errno: %d) %s\n", errno, strerror(errno));
		exit(1);
	}
}

void init_server_socket(const char *argv[]) {
	
	server_addr_length = sizeof(server_address);
	memset(&server_address, 0, server_addr_length);
	server_address.sin_family = AF_INET;

	// aton = address to number 把字符串转化成32bits的二进制数字
	if (inet_aton(argv[1],&server_address.sin_addr) == 0)  
	{
		printf("输入的IP不合法 \n");
		exit(1);
	}
	server_address.sin_port = htons(SERVER_PORT);
}

void say_hello() {
	memset(buffer_receive, 0, sizeof(buffer_receive)); 
	memset(buffer_send, 0, sizeof(buffer_send)); 
	strcpy(buffer_send, "chit-chat begins ~_~");
	fd_temp = send(client_socket_fd, buffer_send, sizeof(buffer_send), 0);
	check_fd(fd_temp, "say hello");
}

// 接收数据 receive
void *thread_receive() {
	while(1) {
		memset(buffer_receive, 0, BUFFER_SIZE);
		int buflen = recv(client_socket_fd, buffer_receive, BUFFER_SIZE, 0);
		check_fd(buflen, "receive");
		if (buflen == 0)
			continue;
		printf("\nserver:    %s", buffer_receive);	
		printf("\nI say:    "); 

		// bye 结束会话
		// trim(buffer_receive);
		if(strcmp(buffer_receive, "bye") == 0) {
			close(client_socket_fd); break;
		}
		sleep(1);	
	}	
}

// 读取并发送数据 send
void *thread_send() {
	while(1) {		    	
		memset(buffer_send, 0, BUFFER_SIZE);
		fgets(buffer_send, BUFFER_SIZE, stdin);       	
		int buflen = send(client_socket_fd, buffer_send, sizeof(buffer_send), 0);
		check_fd(buflen, "send"); 
	}		
}

void begin_conversation() {

	printf(" conversation detected\n\n");
	int err1 = pthread_create(&thread_send_fd, NULL, thread_send, NULL);
	if(err1 != 0) 
		printf("%s\n",strerror(err1)); 
	else 
		printf("send thread created\n");
	int err2 = pthread_create(&thread_receive_fd, NULL, thread_receive, NULL);
	if(err2 != 0) 
		printf("%s\n",strerror(err2)); 
	else 
		printf("receive thread created\n");
}

int main(int argc, char const *argv[])
{
	if (argc != 2) {
		printf(" You must tell me the address of server! \n");
		return 0;
	}

	// 创建 client_socket
	client_socket_fd = socket(AF_INET,SOCK_STREAM,0);
	check_fd(client_socket_fd, "creat socket");
    
	// 初始化服务器的socket
	init_server_socket(argv);

	// 连接
	fd_temp = connect(client_socket_fd, (struct sockaddr*) &server_address, server_addr_length);
	check_fd(fd_temp, "connect");

	// 试探一下能否连通
	//say_hello();
	
	printf("conversation received, chit-chat begins ~_~ \n");

	begin_conversation();	
	pthread_join(thread_send_fd, NULL);
	pthread_join(thread_receive_fd, NULL);
   	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值