基于Erlang开发入门聊天小demo(普通socket(tcp&udp)聊天、otp整合tcp以及websocket聊天、使用Emakefile编译所有项目)及附源码地址、学会入门Erlang

这篇博客介绍了如何使用Erlang开发聊天应用,包括原生socket实现的TCP和UDP聊天,以及基于OTP框架的TCP聊天服务端和WebSocket聊天系统。还详细讲解了项目结构、编译过程以及运行方法,并提供了源码下载链接。
摘要由CSDN通过智能技术生成


注意:erlang的进程式编程,用shell脚本方便管理,应使用linux来学习较好,本项目还可以继续在window环境下执行

1. 项目结构

在这里插入图片描述

2.学会编译erl文件至指定目录

Emakefile 文件,执行方法,在其所在的目录下打开erl终端,输入make :all() 即可编译,内容如下:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 聊天工程-处理运行命令,使用shell脚本方便管理整个工程,里面多个小模块直接使用Emakefile更加方便
%% c(模块名) 单独
%% make :all(). 使用Emakefile
%% emakefile_hd.erl Emakefile编译时处理需要复制的文件,通过erl编译文件实现
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{
   "emakefile_do.erl", [debug_info, {
   i,"include"}, {
   outdir,"."}]}.
{
   "src/socket_chat/*", [debug_info, {
   i,"include"}, {
   outdir,"ebin/socket_chat"}]}.
{
   "src/otp_chat/*", [debug_info, {
   i,"include"}, {
   outdir,"ebin/otp_chat"}]}.
{
   "src/websocket_otp_chat/*", [debug_info, {
   i,"include"}, {
   outdir,"ebin/websocket_otp_chat"}]}.

在这里插入图片描述

3.编译文件目录如图

在这里插入图片描述

4. 如何运行,编译输出后,到底编译的文件夹目录,打开erl终端,然后就可以执行模块的方法了,如这样就启动聊天服务端了

在这里插入图片描述

5.项目代码说明

1.原生socket连接聊天系统
tcp聊天

tcp_server.erl 服务端

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @doc
%%% tcp 服务端
%%% @end
%%% Created : 2023/8/9 19:32
%%%-------------------------------------------------------------------
-module(tcp_server).
%% API
-export([listen_socket/1, start/0]).

-define(SERVER_PORT, 8080).

start() ->
	listen_socket(?SERVER_PORT),
	ok.

%% 监听连接客户端
listen_socket(ServerPort) ->
	{
   ok, ListenSocket} = gen_tcp:listen(ServerPort, [{
   active, false}, {
   reuseaddr, true}]),
	error_logger:info_msg("tcp 服务端 启动成功"),
	accept_connections(ListenSocket).

%%处理客户端连接
accept_connections(ListenSocket) ->
	accept_connections(ListenSocket, []).
accept_connections(ListenSocket, Clients) ->
	{
   ok, ClientSocket} = gen_tcp:accept(ListenSocket),
	error_logger:info_msg("accept_connections:~w~n", [ClientSocket]),
	NewClients = [{
   ClientSocket, undefined} | Clients],
	spawn(fun() -> handle_client(ClientSocket, NewClients) end),
	accept_connections(ListenSocket, NewClients).

%%处理客户端发送的消息
handle_client(ClientSocket, Clients) ->
	{
   ok, SocketData} = gen_tcp:recv(ClientSocket, 0),
	Res = iolist_to_binary(SocketData),
	Result = binary_to_term(Res),
	case Result of
		{
   ok, Msg} = MsgData ->
			io:format("收到消息:socket:~w, msg:~ts~n", [ClientSocket, Msg]),
			broadcast_message(Clients, MsgData);
		Error ->
			error_logger:info_msg("消息格式错误:~w", [Error])
	end,
	handle_client(ClientSocket, Clients).

%%广播消息-支持多人聊天
broadcast_message(Clients, Message) ->
	lists:foreach(fun({
   ClientSocket, _}) ->
		gen_tcp:send(ClientSocket, term_to_binary(Message))
	end, Clients).



tcp_client.erl 客户端

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @doc
%%% tcp 客户端
%%% @end
%%% Created : 2023/8/15 18:54
%%%-------------------------------------------------------------------
-module(tcp_client).

%% API
-export([start/0]).

-define(SERVER_IP, "127.0.0.1").
-define(SERVER_PORT, 8080).

start() ->
	{
   ok, Socket} = gen_tcp:connect(?SERVER_IP, ?SERVER_PORT, [binary, {
   packet, 0}]),
	error_logger:info_msg("tcp客户端 连接成功"),
	spawn(fun() -> loop_input(Socket) end),
	receive_response(Socket).

loop_input(Socket) ->
	MsgData = {
   ok, string:trim(io:get_line("请输入你的消息: "))},
	gen_tcp:send(Socket, term_to_binary(MsgData)),
	loop_input(Socket).

receive_response(Socket) ->
	receive
		{
   tcp, Socket, Bin} ->
			case binary_to_term(Bin) of
				{
   ok, Msg} ->
					io:format("(收到聊天消息):~ts~n", [Msg]);
				Error1 ->
					error_logger:info_msg("Error receiving response: ~w~n", [Error1])
			end;
		Error2 ->
			error_logger:info_msg("Error receiving response: ~w~n", [Error2])
	end,
	receive_response(Socket).
udp聊天

udp_server.erl 服务端

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @doc
%%% udp 服务端
%%% @end
%%% Created : 2023/8/9 19:32
%%%-------------------------------------------------------------------
-module(udp_server).
%% API
-export([start/0]).

-define(SERVER_IP, "127.0.0.1").
-define(SERVER_PORT, 8001).

start() ->
	{
   ok, ListenSocket} = gen_udp:open(?SERVER_PORT, [binary]),
	error_logger:info_msg("udp 服务端 启动成功"),
	receive_response(ListenSocket).

%%处理客户端连接
receive_response(Socket) ->
	receive
		{
   udp, Socket, Host, Port, Bin} ->
			case binary_to_term(Bin) of
				{
   ok, Msg} = MsgData ->
					io:format("收到消息:~ts~n", [Msg]),
					gen_udp:send(Socket, Host, Port, term_to_binary(MsgData)),
					receive_response(Socket);
				Error1 ->
					error_logger:info_msg("Error receiving response: ~w~n", [Error1])
			end;
		Error2 ->
			error_logger:info_msg("Error receiving response: ~w~n", [Error2])
	end,
	receive_response(Socket).


udp_client.erl 客户端

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @doc
%%% udp 客户端
%%% @end
%%% Created : 2023/8/15 18:54
%%%-------------------------------------------------------------------
-module(udp_client).

%% API
-export([start/0]).

-define(SERVER_IP, "localhost").
-define(SERVER_PORT, 8001).

start() ->
	{
   ok, Socket} = gen_udp:open(0, [binary]),
	error_logger:info_msg("udp客户端 连接成功"),
	spawn(fun() -> loop_input(Socket) end),
	receive_response(Socket).

loop_input(Socket) ->
	MsgData = {
   ok, string:trim(io:get_line("请输入你的消息: "))},
	gen_udp:send(Socket, ?SERVER_IP, ?SERVER_PORT, term_to_binary(MsgData)),
	loop_input(Socket).

receive_response(Socket) ->
	receive
		{
   udp, Socket, _Host, _Port, Bin} ->
			case binary_to_term(Bin) of
				{
   ok, Msg} ->
					io:format("(收到聊天消息):~ts~n", [Msg]);
				Error1 ->
					error_logger:info_msg("Error receiving response: ~w~n", [Error1])
			end;
		Error2 ->
			error_logger:info_msg("Error receiving response: ~w~n", [Error2])
	end,
	receive_response(Socket).
2.基于Otp框架搭建tcp服务端进行聊天,客户端其实同理,先自行熟悉OTP框架内容

chat.app 应用层 应用程序描述文件

在Erlang中,chat.app 文件通常是一个应用程序描述文件(.app 文件)。这个文件包含了有关 Erlang 应用程序的元数据,例如应用程序的名称、版本号、模块列表以及其他相关信息。

{
   application, chat,
	[{
   description, "rfos - chat server!"},
		{
   id, "chat"},
		{
   vsn, "0.1"},
		{
   modules, [chat]},
		{
   registered, [chat, chat_server_sup]},
		{
   applications, [kernel, stdlib, sasl]},
		{
   mod, {
   chat, []}},
		{
   env, []}
	]}.

chat.hrl 一些普通宏定义文件

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @copyright (C) 2024,
%%% @doc
%%% 
%%% @end
%%% Created : 02. 四月 2024 15:01
%%%-------------------------------------------------------------------
%%日志封装
-define(INFO(Format), error_logger:info_msg(Format, [])).
-define(INFO(Format, Args), error_logger:info_msg(Format, Args)).

-define(SERVER_IP, "127.0.0.1").
-define(SERVER_PORT, 8080).

-record(state, {
   socket, clients}).

-define(chat_client_list, chat_client_list). % 进程字典名称,用于存储各个聊天接口的连接,广播消息的需要[{ConnectSocket}]

-define(ROLE_PROCESS_EXIT_WAIT, 10).%%角色进程退出时等待多少秒

common_util.erl 普通工具类

%%%-------------------------------------------------------------------
%%% @author rfos
%%% @copyright (C) 2010, rfos
%%% @doc
%%% 普通类 控制
%%% @end
%%%-------------------------------------------------------------------
-module(common_util).
-include("chat.hrl").

-export([manage_applications/6, start_applications/1, stop_applications/1, copy_files/3]).

manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
    Iterate(fun(App, Acc) ->
       case Do(App) of
          ok ->
             ?INFO("manage_applications:~ts~ts", [App, "操作成功!"]),
             [App | Acc];
          {
   error, {
   SkipError, _}} -> Acc;
          {
   error, Reason} ->
             lists:foreach(Undo, Acc),
             throw({
   error, {
   ErrorTag, App, Reason}})
       end
    end, [], Apps),
    ?INFO("app stop success"),
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锐行织梦者

谢谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值