添加聊天工具项目的基本结构和功能实现,包括用户认证、消息处理、文件传输及数据库操作

This commit is contained in:
deastern
2025-06-02 19:15:41 +08:00
parent 64686a2de0
commit f74b59749d
11 changed files with 411 additions and 0 deletions

72
chat_project/server/db.go Normal file
View File

@@ -0,0 +1,72 @@
package main
import (
"database/sql"
"log"
"time"
_ "github.com/mattn/go-sqlite3"
)
var db *sql.DB
func InitDB() {
var err error
db, err = sql.Open("sqlite3", "./chat.db")
if err != nil {
log.Fatalf("打开数据库失败: %v", err)
}
createTableSQL := `
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender TEXT NOT NULL,
receiver TEXT NOT NULL,
content TEXT NOT NULL,
timestamp DATETIME NOT NULL
);
`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Fatalf("创建表失败: %v", err)
}
}
func SaveMessage(sender, receiver, content string) error {
stmt, err := db.Prepare("INSERT INTO messages(sender, receiver, content, timestamp) VALUES (?, ?, ?, ?)")
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(sender, receiver, content, time.Now())
return err
}
func GetMessages(sender, receiver string) ([]Message, error) {
rows, err := db.Query("SELECT sender, receiver, content, timestamp FROM messages WHERE (sender = ? AND receiver = ?) OR (sender = ? AND receiver = ?) ORDER BY timestamp ASC", sender, receiver, receiver, sender)
if err != nil {
return nil, err
}
defer rows.Close()
var messages []Message
for rows.Next() {
var msg Message
var ts string
err = rows.Scan(&msg.Sender, &msg.Receiver, &msg.Content, &ts)
if err != nil {
return nil, err
}
msg.Timestamp, _ = time.Parse(time.RFC3339, ts)
messages = append(messages, msg)
}
return messages, nil
}
type Message struct {
Sender string
Receiver string
Content string
Timestamp time.Time
}

View File

@@ -0,0 +1,59 @@
package main
import (
"fmt"
"io"
"net"
"os"
)
// 服务器端接收文件的示例函数
func ReceiveFile(conn net.Conn, filename string, filesize int64) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
var received int64 = 0
buf := make([]byte, 4096)
for received < filesize {
n, err := conn.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
file.Write(buf[:n])
received += int64(n)
}
fmt.Printf("文件 %s 接收完成,共 %d 字节\n", filename, received)
return nil
}
// 服务器端发送文件的示例函数
func SendFile(conn net.Conn, filepath string) error {
file, err := os.Open(filepath)
if err != nil {
return err
}
defer file.Close()
buf := make([]byte, 4096)
for {
n, err := file.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
_, err = conn.Write(buf[:n])
if err != nil {
return err
}
}
fmt.Printf("文件 %s 发送完成\n", filepath)
return nil
}

View File

@@ -0,0 +1,75 @@
package main
import (
"bufio"
"fmt"
"log"
"net"
"sync"
)
var (
clients = make(map[net.Conn]string) // 连接映射:连接对象到用户名
clientsMu sync.Mutex // 保护clients的互斥锁
)
func main() {
listener, err := net.Listen("tcp", ":8888")
if err != nil {
log.Fatalf("监听端口失败: %v", err)
}
defer listener.Close()
fmt.Println("服务器已启动,监听端口 8888")
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("接受连接失败: %v", err)
continue
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer func() {
// 连接关闭时,移除客户端
clientsMu.Lock()
delete(clients, conn)
clientsMu.Unlock()
conn.Close()
broadcast(fmt.Sprintf("用户退出:%s", conn.RemoteAddr().String()), "系统")
fmt.Printf("客户端断开:%s\n", conn.RemoteAddr().String())
}()
// 添加新连接
clientsMu.Lock()
clients[conn] = conn.RemoteAddr().String()
clientsMu.Unlock()
// 通知所有客户端有新用户加入
broadcast(fmt.Sprintf("新用户加入:%s", conn.RemoteAddr().String()), "系统")
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
msg := scanner.Text()
sender := clients[conn]
broadcast(msg, sender)
}
if err := scanner.Err(); err != nil {
log.Printf("读取消息错误: %v", err)
}
}
func broadcast(message, sender string) {
clientsMu.Lock()
defer clientsMu.Unlock()
for c := range clients {
if c != nil {
_, err := fmt.Fprintf(c, "[%s] %s\n", sender, message)
if err != nil {
log.Printf("广播失败: %v", err)
}
}
}
}

BIN
chat_project/server/server Normal file

Binary file not shown.