C语言socket TCP/IP通讯Server/Client程序(Ubuntu Linux 24.04环境)

news/2024/7/3 16:35:29

继上篇文章介绍了Ubuntu Linux 24.04 C语言TCP/IP socket编程基础知识,本文将用C语言在Ubuntu Linux 24.04环境下开发一对使用socket进行TCP/IP通讯的Server/Client程序,实现的功能是:

1. 当client连上server时,显示连接成功的信息,然后等待client的输入。

2. 将client的输入在server端显示。

socket_server.c文件的内容如下:

/*
编译生成可执行程序(Ubuntu Linux 24.04)
# gcc ./socket_server.c -o socket_server
# ./socket_server

查看防火墙的状态:(国内的云服务器80,443,8080,8443是备案端口,必须备案以后才能从外网访问,注意避免使用)
# ufw status
# ufw allow 8888
查看端口是否被其它程序占用
# sudo apt lsof
# lsof -i:8888
*/

#include <stdio.h>      // printf
#include <string.h>	    // strlen(char*)
#include <unistd.h>     // close(int file_descriptor): close socket
#include <sys/socket.h> // socket(), bind(), accept(), etc
#include <netdb.h>      // gethostbyname(char* domain_name)
#include <arpa/inet.h>	// long inet_addr(char* ip_address) : convert ip string to long int format

#define SERVER_LISTEN_PORT 8888
#define SOCK_BUF_SIZE 10241
#define SOCK_BUF_SIZE1 10240 // subtract 1 for the null terminator at the buf end
#define SOCK_CONN_QUEUE_MAX 3


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

	int listen_sock, sock;
	struct sockaddr_in server_addr, client_addr;
	socklen_t addrlen = sizeof(struct sockaddr_in);

  int client_count=0;	char *client_ip; int client_port;

	char buffer[SOCK_BUF_SIZE] = { 0 };
	long recv_size=0, send_size=0;

	if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create server listen socket failed"); goto fail; 	}
	printf("create server listen socket succeed\n");

	server_addr.sin_family = AF_INET; // IPv4
	server_addr.sin_addr.s_addr = INADDR_ANY;	// 监听所有本地IP地址
	server_addr.sin_port = htons(SERVER_LISTEN_PORT);
	if (bind(listen_sock, (struct sockaddr*)&server_addr, addrlen) == -1) { perror("server listen socket bind to ip:port failed"); goto fail_close; }
	printf("bind server listen socket to port %d succeed\n", SERVER_LISTEN_PORT);

	if (listen(listen_sock, SOCK_CONN_QUEUE_MAX) == -1) { perror("server socket start listening failed"); goto fail_close; }
	printf("server socket starts listening ...\n");

	while((sock	= accept(listen_sock, (struct sockaddr*)&client_addr,	&addrlen)) > 0)
	{			
		client_count++;
		client_ip = inet_ntoa(client_addr.sin_addr); client_port = ntohs(client_addr.sin_port);
		printf("%d --------------- \nserver socket accepted a client connection:  %s:%d ---------------\n", client_count, client_ip, client_port);
		// if(set_socket_options(sock) == -1) goto end_close_client;
		while((recv_size = recv(sock, buffer, SOCK_BUF_SIZE1, 0))>0)
		{
			if(recv_size<0) { printf("receive from client failed\n"); goto end_close_client;}
			buffer[recv_size]=0; // set string end
			printf("received %ld bytes data: \n%s\n", recv_size, buffer);
		}
		//send_size = send(sock, hello, strlen(hello), 0); if(send_size<0) { printf("write to client failed\n"); goto end_close_client;}
		//printf("Hello message sent\n");
		end_close_client: close(sock);
		printf("waiting for next client ...\n");
	}

	close(listen_sock); goto succeed;
	fail_close: close(listen_sock); goto fail;
	succeed: return r;
	fail: r=1; return r;
}

socket_client.c文件的内容如下:

/*
编译生成可执行程序(Ubuntu Linux 24.04)
# gcc ./socket_client.c -o socket_client
# ./socket_client
*/

#include <stdio.h>      // printf
#include <string.h>	    // strlen(char*)
#include <stdlib.h>     // free(*memory)
#include <unistd.h>     // close(int file_descriptor): close socket
#include <sys/socket.h> // socket(), bind(), accept(), etc
#include <netdb.h>      // gethostbyname(char* domain_name)
#include <arpa/inet.h>	// long inet_addr(char* ip_address) : convert ip string to long int format

#define SERVER_LISTEN_PORT 8888
#define SOCK_BUF_SIZE 10241
#define SOCK_BUF_SIZE1 10240 // subtract 1 for the null terminator at the buf end
#define SERVER_DOMAIN_NAME "idealand.space"
#define BUDA_F(p) if(p){ free(p); p=NULL; } 


/* 通过域名获取socket可用的ip地址格式,用于连接server socket 
   hostname: 例如 idealand.space */
struct in_addr * get_sock_addr(char *hostname)
{
	printf("resolving %s to IP address...\n" , hostname);
	struct hostent *he;
	struct in_addr **addr_list; // data in struct in_addr is long int ip
	int i;
		
	if ( (he = gethostbyname( hostname ) ) == NULL )  goto fail;
	
	addr_list = (struct in_addr **) he->h_addr_list;
	struct in_addr * ip_addr=NULL;	
	for(i = 0; (ip_addr=addr_list[i]) != NULL; i++) 
	{
		printf("%d: %s\n", i+1 , inet_ntoa(*ip_addr) ); // inet_ntoa convert an IP address in long int format to dotted format
		goto succeed; // use the first IP address 
	}	
	if(ip_addr==NULL) goto fail;

	succeed: return ip_addr;
	fail: printf("gethostbyname for %s failed", hostname); return NULL;
}

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

	struct in_addr * ip_addr=get_sock_addr(SERVER_DOMAIN_NAME);
	if(ip_addr==NULL) goto fail;

	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET; // IPv4
	server_addr.sin_addr = *ip_addr;	
	server_addr.sin_port = htons(SERVER_LISTEN_PORT);
	socklen_t addrlen = sizeof(struct sockaddr_in);

	int sock;
	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create client socket failed\n"); goto fail; 	}
	printf("create client socket succeed\n");

	if (connect(sock , (struct sockaddr *)&server_addr , addrlen) == -1) { perror("connect to server failed\n"); goto fail_close; }
	printf("connect to server succeed\n");

	char *line = NULL; size_t len = 0; ssize_t read;
	while((read = getline(&line, &len, stdin)) > 0)
	{			
		if(send(sock, line, read,	0) <= 0) goto fail_close;
		BUDA_F(line);
	}
	BUDA_F(line);

	close(sock); goto succeed;
	fail_close: close(sock); goto fail;
	succeed: return r;
	fail: r=1; return r;
}


http://lihuaxi.xjx100.cn/news/2218129.html

相关文章

Python 数据持久化:使用 SQLite3 进行简单而强大的数据存储

&#x1f340; 前言 博客地址&#xff1a; CSDN&#xff1a;https://blog.csdn.net/powerbiubiu &#x1f44b; 简介 SQLite3是一种轻量级嵌入式数据库引擎&#xff0c;它在Python中被广泛使用。SQLite3通常已经包含在Python标准库中&#xff0c;无需额外安装。你只需导入 s…

522. 最长特殊序列 II

题目 给定字符串列表 strs &#xff0c;返回其中最长的特殊序列的长度。如果最长特殊序列不存在&#xff0c;返回 -1。 特殊序列定义如下&#xff1a;该序列为某字符串独有的子序列&#xff08;即不能是其他字符串的子序列&#xff09;。 字符串 s 的子序列可以通过删去字符…

使用超声波麦克风阵列预测数控机床刀具磨损

预测性维护是使用传感器数据来推断机器状态&#xff0c;并从这些传感器数据中检测出在故障发生之前存在的缺陷或故障的过程。预测性维护在所有工业领域都是一种日益增长的趋势&#xff0c;包括轴承故障检测、齿轮磨损检测或往复式机器中的活塞磨损等许多其他例子。在预测性维护…

文档项目:攻坚克难

鉴于交流离心机存在的缺点&#xff1a;转速相对偏差、稳定精度不够高&#xff1b;带负载能力受外界扰动后&#xff0c;波动较大&#xff1b;寿命短&#xff0c;研究所各相关部门成立组成技术攻关团队&#xff0c;齐心协力&#xff0c;攻坚克难&#xff0c;在摸索中突破创新&…

【热】大数据信用报告查询平台哪个比较好?这个平台值得一试!

在当今数字化时代&#xff0c;大数据技术的发展为个人和企业提供了更便捷、精准的信用报告查询服务。选择一个优秀的大数据信用报告查询平台至关重要&#xff0c;它直接影响到您获取信用信息的准确性和全面性。 首先&#xff0c;选择大数据信用报告查询平台时&#xff0c;您可以…

TDengine防火墙配置

TDengine 部署时建议禁用防火墙&#xff0c;对于有安全要求必须启用防火墙的的场景&#xff0c;可以只开放 TDengine 相关端口。 TDengine 端口列表 TDengine 不同版本使用的端口也不尽相同&#xff0c;以下是不同版本的端口列表。 TDengine 2.x 端口协议描述6030-6035TCP/…

JupyterLab使用指南(三):JupyterLab的Cell详细介绍

JupyterLab Cell 使用教程 JupyterLab 的 cell 是一种强大的工具&#xff0c;提供了编写、执行、展示和记录的全方位支持&#xff0c;使得复杂的计算任务变得简单直观。通过熟练掌握 cell 的各种操作和快捷键&#xff0c;用户可以显著提高工作效率&#xff0c;专注于解决实际问…

web前端defer:深度解析与实用指南

web前端defer&#xff1a;深度解析与实用指南 在web前端开发中&#xff0c;defer是一个关键的属性&#xff0c;它影响着脚本的加载和执行方式。然而&#xff0c;对于许多开发者来说&#xff0c;defer的真正含义和用法却常常带来困惑。本文将通过四个方面、五个方面、六个方面和…