---
title: '網路程式設計期末專題'
tags: 網路程式設計
---
# 網路程式設計期末專題
目錄
[TOC]
---
## 專題進度報告
1. 成員姓名
* 1072926 林哲緯
* 1072940 黃梓豪
2. 作品描述
* 實現可以輕鬆訂餐的校園美食外送平台,使用者可以使用簡潔的介面來訂購校園餐點。
* 身為大學生,應該都有過「不想上課地點與學餐兩邊跑」或「不想出去宿舍吃飯」的經驗,此平台乃是解決此問題的最佳之道,僅需支付些許的外送費,即可訂購校內餐點,由外送人員幫您外帶餐點,並送交至您指定的地點。
* 因此,開發了這個「貓貓餓了」,希望想訂餐的同學能夠以單筆 15 元便宜的價格當外送員以及工程師的薪水,讓原本目的地就是你那棟樓的人順便幫你外帶。
3. 技術
* 前端
* Unity(C#)
* socket
* 後端
* PHP(socket)
* MySQL
* Apache
* Linux
4. 困難點或創新點
* 困難點
* 礙於時間不足,無法設計出精美又流暢的 UI 界面供使用者使用。
* 初次使用其他語言撰寫 socket 程式,須熟悉語法概念。
* 創新點
* 有別於一般外送平台僅針對一般使用者,本平台為專為校園環境開發之美食外送平台
* 有別於一般平台使用 HTTP 協定作為 client - server 端間的溝通渠道,本平台使用 socket 作為溝通方式。
5. 專題進度
* 進度正常
* 前端 UI 界面設計完成,剩餘 client 端網路連接部份
* 後端系統架構設計完成,剩餘 server 端網路連接部份
6. 所遇到的問題
* 原本此專題想用 Android(Java) 來實踐,礙於時間關係,僅能改用 Unity(C#) 來實現
* 目前狀況尚不須要與老師討論
---
## 期末報告
### 書面報告
1. 題目,小組成員,口頭報告影片youtube網址
* **題目** :
* 貓貓餓了 - 校園美食外送平台
* **成員** :
* 1072926 林哲緯
* 1072940 黃梓豪
* **口頭報告影片youtube網址** :
* https://www.youtube.com/watch?v=NeWr3pg3bas
2. 簡要說明作品
* 實現可以輕鬆訂餐的校園美食外送平台,使用者可以使用簡潔的介面來訂購校園餐點。
* 身為大學生,應該都有過「不想上課地點與學餐兩邊跑」或「不想出去宿舍吃飯」的經驗,此平台乃是解決此問題的最佳之道,僅需支付些許的外送費,即可訂購校內餐點,由外送人員幫您外帶餐點,並送交至您指定的地點。
* 因此,開發了這個「貓貓餓了」,希望想訂餐的同學能夠以單筆 15 元便宜的價格當外送員以及工程師的薪水,讓原本目的地就是你那棟樓的人順便幫你外帶。
3. 作品執行過程說明(配合畫面)
1. 先開啟Server後端服務
(使用Select Socket 建立多工)

2. 開啟Client前端服務並登入帳密
* Client端
(利用Tcp Socket 連線 Client->Server)

* Server端

3. 進入Client Interface

4. 點選About 顯示此應用程式介紹

5. 進入點餐畫面並確認點選餐點
* 校區

* 建築物與教室空間

* 餐廳與餐點選擇


6. 餐點確認並送出訂單
* Client端
(利用Tcp Socket 連線 Client->Server)

* Server端(紅色圈起處)

7. 顯示是否訂餐成功
(利用Tcp Socket 連線 Server->Client)

8. 進入查詢訂單先跟Server拿取此帳號共有幾筆訂單
* Client端
(先利用Udp Socket 連線 Client->Server 送出要求)

* Server端(紅色圈起處)
(再利用Udp Socket 連線 Server->Client 拿到筆數)

9. 送出訂單查詢
* Client端
(先利用Tcp Socket 連線 Client->Server 送出訂單)

* Server端(紅色圈起處)
(再利用Tcp Socket 連線 Server->Client 拿到資訊)

10. 登入餐廳端來查詢與改變訂單狀態
* 餐廳端
(餐廳端利用HTTP 連線)


* Client (黃色圈起處)
(利用Tcp Socket 連線 Server->Client 拿到更新資訊)

11. 登入外送員端來查詢與改變外送單狀態
* 外送端
(外送員端利用HTTP 連線)


* Client (黃色圈起處)
(利用Tcp Socket 連線 Server->Client 拿到更新資訊)

4. 本作品架構
* 一個Server對多個Client
* 多工
* 群播(UDP部分)
5. 本作品的功能(包含特色、困難、挑戰、花最多精力)
* 作品特色
> 本作品是以學校和學生為導向,專為校園環境打造的美食外送平台,現在疫情嚴峻,講求無接觸送餐,若使用一般的外送平台,送餐的外送員在整個城市內滿街奔馳,又進到學校內送餐,恐怕會造成防疫上的一些疑慮,使用校內的平台來訂購餐點,外送員皆是本校的學生,大家出入校門都有測量過體溫,有初步的健康檢測,會比較有保障。
> 一般的外送平台,僅能送餐到校門口,而本平台的外送員可將餐點送至教室門口,對於不想出系館用餐的學生,使用本平台肯定是最家的解決之道。
> 本平台不但提供送餐的服務,可讓使用者填飽肚子,另外還有一個功能是可以提供學生一個打工的機會,設計這個平台當初的構想是可以利用剛好要去某個系館的學生,將餐點順路送去該系館,這樣一來,這個平台不需要龐大的資金,只要有一定的學生人數就可以運作。
* 困難與挑戰
> 在製作這個專題中面臨到的困難主要是時間的因素,我們要在極短的時間內將一個外送平台建構起來會花上非常多的時間,因此決定使用先前製作的系統來加以改良,才能在短暫的時間內完成初這次的專題。
> 由於先前的平台不是使用C語言來撰寫的,所以我們要學習其他語言socket的使用方式,我們在學習的方面,也花上了不少的時間。
6. 本作品使用到課程所教的技術,以及其他自學的技術
* **前端** :
* Unity(C#)
* socket
* **後端** :
* PHP(socket)
* MySQL
* Apache
* Linux
7. 人員分工與時間分配
* **人員分工** :
* 黃梓豪 : 利用 Unity 建立前端服務
* 林哲緯 : 利用 PHP 與 MySQL 建立系統後端服務
* **時間分配** :
* 都是利用課餘時間來實作期末專案。
* 每周找時間互相Demo兩端的部分功能,然後進行討論需修改的地方。
8. 程式碼
* Server : https://github.com/linwebs/school-delivery-platform
* Client : https://github.com/ianzih/School_Delivery_Platform_Client
---
## 訂單狀態
```json=
{
0: "訂單未成立", // 不會發生此情況
1: "新訂單", // 顧客剛下單
2: "餐點準備中", // 店家已確認訂單,開始準備餐點
3: "等待送餐中", // 店家完成餐點,等待外送員取餐
4: "餐點外送中", // 外送員已取餐,前往顧客指定的地點
5: "餐點已送達", // 外送員已抵達顧客指定的地點,等待顧客取餐
6: "訂單已完成", // 顧客已取餐
7: "訂單已取消", // 顧客取消訂單,仍在狀態 1 顧客可取消訂單
}
```
---
## 溝通方式
### socket
傳輸內容: `size(4) + json`
盡量以最小化傳輸,如: 刪除換行及空白。
ex: 登入帳號<small>(共55字)</small>
#### client -> server
```js
0051{"action":"login","account":"abc","password":"123"}
```
#### server -> client
```js
0088{"action":"login","status":"ok","msg":"登入成功","token":"e5e8b6e29f9877eb140976c8ea3f9830"}
```
### 伺服器位址
IP Address: 35.229.205.65
Hostname: socket.delivery.csie.linwebs.tw
### 通訊埠 Port
* 5701 TCP 多工
* 5702 UDP 多工
:::warning
為節省資源,伺服器socket服務目前為關閉狀態!
:::
---
## 登入 (TCP 多工)
取得 token
### client -> server
```json=
{
"action": "login"
"account": "abc",
"password": "123"
}
```
### server -> client
#### 登入成功
```json=
{
"action": "login"
"status": "ok",
"msg": "登入成功",
"token": "hasodijasid",
"type": "customer"
}
```
#### 登入失敗
```json=
{
"action": "login"
"status": "error",
"msg": "帳號密碼錯誤",
"token": null,
"type": null
}
```
## 登出
讓 token 失效
### client -> server
```json=
{
"action": "logout"
"token": "hasodijasid"
}
```
### server -> client
#### 登入成功
```json=
{
"action": "logout"
"status": "ok",
"msg": "登出成功"
}
```
#### 登入失敗
```json=
{
"action": "logout"
"status": "error",
"msg": "登出失敗"
}
```
---
## 送訂單 (TCP 多工)
### client -> server
```json
{
"action": "send_ticket"
"token": "hasodijasid",
"area": 1,
"build": 1,
"room": 1,
"shop": 1,
"meal": 1,
"quantity": 5
}
```
### server -> client
#### 成功送出
```json
{
"action": "send_ticket"
"status": "ok",
"msg": "成功送出訂單",
"id": 3
}
```
#### 送出失敗
msg: 錯誤訊息
```json
{
"action": "send_ticket"
"status": "error",
"msg": "未登入",
"id": null
}
```
---
## 訂單筆數 (UDP 多工 群播)
### client -> server
```json
{
"action": "count_ticket"
"token": "hasodijasid"
}
```
### server -> clientserver
#### 查詢成功
```json
{
"action": "count_ticket"
"status": "ok",
"msg": "訂單筆數查詢成功",
"count": 50
}
```
#### 查詢失敗
msg: 錯誤訊息
```json
{
"action": "ticket_status"
"status": "error",
"msg": "伺服器維護中",
"count": null
}
```
---
## 單一訂單狀態 (TCP 多工)
### client -> server
```json
{
"action": "ticket_status"
"token": "hasodijasid",
"id": 10
}
```
### server -> client
#### 查詢成功
```json
{
"action": "ticket_status",
"status": "ok",
"msg": "訂單狀態查詢成功",
"id": 10,
"area": 1,
"build": 1,
"room": 1,
"shop": 1,
"meal": 1,
"quantity": 5,
"order_status": 5
}
```
#### 查詢失敗
msg: 錯誤訊息
```json
{
"action": "ticket_status"
"status": "error",
"msg": "伺服器維護中",
"id": null,
"area": null,
"build": null,
"room": null,
"shop": null,
"meal": null,
"quantity": null,
"order_status": null
}
```
---
## ID 編號表
### 校區
```json=
"area": [
1:"蘭潭校區",
2:"新民校區",
3:"民雄校區",
4:"林森校區"
]
```
### 建築物
```json=
"build": [
1:"行政中心", 2:"理工大樓", 3:"學生宿舍", // [蘭潭]
4:"管理學院A", 5:"管理學院B", 6:"學生宿舍" // [新民]
7:"行政大樓", 8:"人文館", 9:"圖書館" // [民雄]
10:"輔導大樓", 11:"圖書館" // [林森]
]
```
### 空間
```json=
"room": [
1:"教務處", 2:"學務處", 3:"瑞穗廳", // [蘭潭] 行政中心
4:"資工系辦", 5:"401教室", 6:"理工學院辦公室", // [蘭潭] 理工大樓
7:"五舍", 8:"一舍", 9:"宿舍辦公室", // [蘭潭] 學生宿舍
10:"1F", // [新民] 管理學院A
11:"1F", // [新民] 管理學院B
12:"門口", 13:"宿舍辦公室", // [新民] 學生宿舍
14:"1F", 15:"2F", 16:"門口", // [民雄] 行政大樓
17:"1F", 18:"門口", // [民雄] 人文館
19:"門口", 20:"圖書辦公室", // [民雄] 圖書館
21:"1F", 22:"門口", // [林森] 輔導大樓
23:"門口", 24:"圖書辦公室" // [林森] 圖書館
]
```
### 店家
```json=
"shop": [
1:"學員簡速餐", 2:"卡好喫手工大水餃", 3:"陽光雞肉飯", // [蘭潭]
4:"滿客屋餐廳", // [新民]
5:"學園餐廳", 6:"京品餐飲" // [民雄]
]
```
### 餐點
```json=
"meal": [
1:"黃金大豬便當", 2:"排骨便當", 3:"照燒雞排便當", // [蘭潭] 學園簡速餐
4:"水餃(小份)", 5:"鍋貼(小份)", // [蘭潭] 卡好喫手工大水餃
6:"雞肉飯", 7:"超大雞排飯", // [蘭潭] 陽光雞肉飯
8:"經濟便當", // [新民] 滿客屋餐廳
9:"經濟便當", // [民雄] 學園餐廳
10:"牛排" // [民雄] 京品餐飲
]
```
### 使用者
帳號與密碼相同
```json=
"user": [
4:"user12", 18:"user13", 19:"user14", 20:"user15", // 一般使用者帳號
22: "user21", 23:"user22", 24:"user23", 25:"user24", // 外送員帳號
7:"user203", // 店家帳號 [蘭潭] 學園簡速餐
9:"user205", // 店家帳號 [蘭潭] 卡好喫手工大水餃
10:"shop206", // 店家帳號 [蘭潭] 陽光雞肉飯
17:"shop801", // 店家帳號 [新民] 滿客屋餐廳
15:"shop501", // 店家帳號 [民雄] 學園餐廳
16:"shop502", // 店家帳號 [民雄] 京品餐飲
]
```
## 範例程式
### Python
#### TCP socket 使用者登入 [login]
```python=
import socket
import time
hostname = 'socket.delivery.csie.linwebs.tw'
port = 5701
print("Login to delivery platform socker version");
account = input("Input account: ")
password = input("Input password: ")
#account = "user11"
#password = "user11"
msg = '{"action":"login","account":"' + account + '","password":"' + password + '"}'
send_msg = ''
if(len(msg) < 10):
send_msg = '000'
elif(len(msg) < 100):
send_msg = '00'
elif(len(msg) < 1000):
send_msg = '0'
send_msg += str(len(msg))
send_msg += msg
ip = socket.gethostbyname(hostname)
print("Server IP:", ip)
print("Send:", send_msg)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip, port))
client.send(send_msg.encode())
recv_msg = str(client.recv(8192), encoding='utf-8')
print("Receive:", recv_msg)
client.send('exit'.encode())
client.close()
```
#### TCP socket 送出訂單 [send_ticket]
```python=
import socket
import time
hostname = 'socket.delivery.csie.linwebs.tw'
port = 5701
print("Login to delivery platform socker version");
area = input("Input area id: ")
build = input("Input build id: ")
room = input("Input room id: ")
shop = input("Input shop id: ")
meal = input("Input meal id: ")
quantity = input("Input quantity: ")
#area = "1"
#build = "1"
#room = "1"
#shop = "1"
#meal = "1"
#quantity = "5"
msg = '{"action":"send_ticket","token":"57b89d871d5969a6f5a5f47c9a648dc7","area":' + area + ',"build":' + build + ',"room":' + room + ',"shop":' + shop + ',"meal":' + meal + ',"quantity":' + quantity + '}'
send_msg = ''
if(len(msg) < 10):
send_msg = '000'
elif(len(msg) < 100):
send_msg = '00'
elif(len(msg) < 1000):
send_msg = '0'
send_msg += str(len(msg))
send_msg += msg
ip = socket.gethostbyname(hostname)
print("Server IP:", ip)
print("Send:", send_msg)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip, port))
client.send(send_msg.encode())
recv_msg = str(client.recv(8192), encoding='utf-8')
print("Receive:", recv_msg)
client.send('exit'.encode())
client.close()
```
#### UDP socket 查詢訂單筆數 [count_ticket]
```python=
import socket
import time
hostname = 'socket.delivery.csie.linwebs.tw'
port = 5702
print("Login to delivery platform socker version");
msg = '{"action":"count_ticket","token":"57b89d871d5969a6f5a5f47c9a648dc7"}'
send_msg = ''
if(len(msg) < 10):
send_msg = '000'
elif(len(msg) < 100):
send_msg = '00'
elif(len(msg) < 1000):
send_msg = '0'
send_msg += str(len(msg))
send_msg += msg
ip = socket.gethostbyname(hostname)
print("Server IP:", ip)
print("Send:", send_msg)
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.sendto(send_msg.encode(), (ip, port))
recv_msg = str(client.recv(8192), encoding='utf-8')
print("Receive:", recv_msg)
#client.sendto('exit'.encode(), (ip, port))
client.close()
```
#### TCP socket 查詢單一訂單狀態 [ticket_status]
```python=
import socket
import time
hostname = 'socket.delivery.csie.linwebs.tw'
port = 5701
print("Login to delivery platform socker version");
ticket = input("Input ticket id: ")
#ticket = "1"
msg = '{"action":"ticket_status","token":"86bb190f24e41ee1d3085156b2c93513","id":' + ticket + '}'
send_msg = ''
if(len(msg) < 10):
send_msg = '000'
elif(len(msg) < 100):
send_msg = '00'
elif(len(msg) < 1000):
send_msg = '0'
send_msg += str(len(msg))
send_msg += msg
ip = socket.gethostbyname(hostname)
print("Server IP:", ip)
print("Send:", send_msg)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip, port))
client.send(send_msg.encode())
recv_msg = str(client.recv(8192), encoding='utf-8')
print("Receive:", recv_msg)
client.send('exit'.encode())
client.close()
```