【发布时间】:2021-11-11 22:41:51
【问题描述】:
在一个 react-native 项目中,我尝试使用 websockets (socket.io-client/socket.io) 将 base64 编码的字符串从客户端传输到服务器,然后再传输到另一个客户端。
我期待什么:
- base64 图像字符串被发送到服务器并且服务器记录“[Data Received]”
- 服务器随后发出“server_send_data”,接收客户端侦听器接收 base64 编码字符串
我正在经历什么:
- base64 编码的图片字符串编码成功
- 发送客户端成功发出事件
- 服务器然后记录“[客户端断开连接] ...”
- 接收客户端未收到任何事件
Server.js io/socket相关代码:
io.on("connection", socket => {
console.log('\n[ Connected To Client ]\n', socket.id)
initRoom(socket)
handleReceivedData(socket)
socket.on('disconnect', () => {
console.log('\n[ Client Disconnected ]\n', connectedAccounts)
delete connectedAccounts
})
socket.on('client_send_data', e => {
console.log(socket.id, 'sent', e)
socket.to(e.account_id).emit('server_send_data', e.data)
})
});
const initRoom = socket => {
socket.emit('server_join_room')
socket.on('client_join_room', accountId => {
if (connectedAccounts.hasOwnProperty(accountId)) {
const socketIds = connectedAccounts[accountId]['socket_ids']
socketIds.push(socket.id)
} else {
connectedAccounts[accountId] = {
inProgress: true,
socket_ids: [socket.id]
}
}
socket.join(accountId)
})
}
const handleReceivedData = socket => {
socket.on('admin_data_send', e => {
console.log('[ Data Received ]')
const { account_id, data } = e
io.to(account_id).emit('display_data_send', data)
})
}
照片选择器(发件人):
export default Photo = ({ navigation }) => {
const [photoURI, onPhotoURI] = useState('')
const openPicker = () => {
ImagePicker.openCamera({
cropping: false,
includeBase64: true
})
.then(async image => {
onPhotoURI(image.data)
console.log('[ photo ]:', image)
await AsyncStorage.removeItem('some_key')
await AsyncStorage.setItem('some_key', String(image.data))
})
.catch(e => alert(e))
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'gray' }}>
<Text>Photo Data Stored: {photoURI !== '' ? 'True' : 'False'}</Text>
<Pressable onPress={openPicker}>
<Text>Take Picture</Text>
</Pressable>
</SafeAreaView>
)
}
sendPic = async () => {
console.log('[ Attempting to send Data to server ]')
this.test.emit('admin_data_send', {
account_id: ACCOUNT_ID,
data: this.state.photoURI
})
}
首页(客户端)
class Home extends React.Component {
constructor(props) {
super(props)
this.state = {
socketId: '',
photoBase64: '',
readyForSync: false,
displayData: null
}
this.test = null
}
componentDidMount() {
this.initSocket()
}
async componentDidUpdate() {
try {
const stored = await AsyncStorage.getItem('some_key')
this.setState({ photoBase64: stored })
} catch (e) {
alert(e)
}
}
initSocket = async () => {
const endpoint = await isEmulator() ? emulator_socket : socket
this.test = io(endpoint)
this.test.on("connect", async () => {
console.log(`${await isEmulator() ? '[ Emulator Connected ]' : '[ Physical Connected ]'}`, 'Endpoint:', endpoint, 'Id:', this.test.id)
this.setState({ socketId: this.test.id })
});
this.test.on("disconnect", () => {
console.log('[ disconnected ]', this.test.id); // undefined
});
this.test.on('server_join_room', () => {
this.test.emit('client_join_room', ACCOUNT_ID)
})
this.test.on('display_data_send', e => {
console.log('[ Display Data Recevied From Server ]')
this.setState({ displayData: e })
})
}
sync = async () => {
this.setState({ readyForSync: true })
console.log('[ Sync Started ]')
this.test.emit('display_ready', {account_id: ACCOUNT_ID})
}
sendPic = async () => {
const endpoint = await isEmulator() ? emulator_socket : socket
console.log('[ Attempting to send Data to server ]')
// divide base64 into 3 segments
console.log('[ base64 length ]:', this.state.photoURI.length)
// loop the emit
this.test.emit('admin_data_send', {
account_id: ACCOUNT_ID,
data: this.state.photoBase64
})
}
render() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#d1d1d1' }}>
{this.state.readyForSync ? (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator animating={true} color="#333" size="large" />
<Text>Awaiting Data From Admin Device...</Text>
{
this.state.displayData !== null && (
<View style={{ width: 200, height: 200 }}>
<Image src={{ uri: `data:image/jpeg;base64,${this.state.displayData}` }} />
</View>
)
}
</View>
) : (
<>
<Text style={{ textAlign: 'center', fontSize: 20, fontWeight: 'bold', marginTop: 20 }}>{Platform.isTV ? 'TV App' : Platform.OS}</Text>
<Text style={{ textAlign: 'center', fontSize: 20, fontWeight: 'bold', marginTop: 20 }}>Socket ID: {this.state.socketId}</Text>
<Pressable style={styles.press} onPress={this.sync}>
<Text> SYNC APP </Text>
</Pressable>
<Pressable style={styles.press} onPress={() => this.props.navigation.navigate('Photo')}>
<Text> TAKE PIC </Text>
</Pressable>
<Pressable style={styles.press} onPress={this.sendPic}>
<Text> SEND PIC </Text>
<Text>{this.state.photoBase64}</Text>
</Pressable>
</>
)}
</SafeAreaView>
)
}
}
如何确保连接没有丢失,数据被服务器接收并成功传输回接收客户端?
【问题讨论】:
-
一个minimal reproducible example,请。没有关于如何使用您的客户的代码。
-
@x00 为你更新
-
可能有很多不同的原因。现在我们不确定这是客户端还是服务器的问题。为确保它在客户端(移动应用程序)上,请尝试先使用工具将大小图像转换为 base64(base64-image.de),然后使用 Postman 之类的工具将其发送到服务器。如果成功,那么只需增加你的超时时间
socket.heartbeatTimeout = 30000;,否则它是服务器的问题
标签: reactjs react-native websocket socket.io