【发布时间】:2021-03-17 10:35:27
【问题描述】:
我有一个项目,我需要通过套接字发送文件进行简单的聊天。我想知道 C 中的套接字编程中是否有任何函数可以让我检查现有连接(我需要向每个连接的客户端发送消息)。我试图通过创建一个数组并将我的套接字保存到它来做到这一点,但是由于fork() 它不起作用,每个客户端都有自己的数组并且它们不匹配。我的服务器是用 C 编写的,我的客户端是用 Python 编写的。以下是我的代码:
服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9992
int main(){
char separator[4];
int iterator = 0;
int clients[32];
separator[0] = '|';
int sockfd, ret;
char name[32];
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Server Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
perror("");
printf("[-]Error in binding.\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if(listen(sockfd, 10) == 0){
printf("[+]Listening....\n");
}else{
perror("");
printf("[-]Error in binding.------\n");
}
while(1){
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
printf("%i", newSocket);
for (size_t i = 0; i <= iterator; i++) {
// printf("%i\n", iterator);
if(clients[i] == 0){
clients[i] = newSocket;
}
else if(i == iterator){
clients[iterator] = newSocket;
iterator ++;
break;
}
}
if(newSocket < 0){
perror("");
printf("new socket < 0");
exit(1);
}
printf("Connection accepted from %s:%d ", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
recv(newSocket, name, 32, 0 );
printf("%s \n", name);
if((childpid = fork()) == 0){
// perror("");
// close(sockfd);
while(1){
for (size_t i = 0; i < iterator; i++) {
printf("%i\n", clients[i]);
}
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, "/exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
perror("");
// deleting disconnecting client from array of clients
for (int i = 0; i < iterator; i++) {
// printf(clients[i]);
if(clients[i] == newSocket){
clients[i] = 0;
printf("Element deleted \n");
}
break;
}
break;
}else{
if(strcmp(buffer, "/who") == 0){
perror("");
for (size_t i = 0; i < iterator; i++) {
printf("%i\n", clients[i]);
bzero(buffer, sizeof(buffer));
}
}
perror("");
printf("%s: %s\n",name, buffer);
for (size_t i = 0; i < iterator; i++) //sending message to every client {
send(clients[i], name, strlen(name), 0);
send(clients[i], separator, strlen(separator), 0);
send(clients[i], buffer, strlen(buffer), 0);
}
bzero(buffer, sizeof(buffer));
// bzero(name, sizeof(name));
}
}
}
}
close(newSocket);
// perror("");
return 0;
}
我的客户端.py:
import socket
import sys
import time
host = '127.0.0.1'
port = 9992
buffer = ''
# create socket
print('# Creating socket')
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print('Failed to create socket')
sys.exit()
print('# Getting remote IP address')
try:
remote_ip = socket.gethostbyname( host )
except socket.gaierror:
print('Hostname could not be resolved. Exiting')
sys.exit()
# Connect to remote server
print('# Connecting to server, ' + host + ' (' + remote_ip + ')')
name = input("What will be your name?: ")
namePY = name
name += "\0"
s.connect((remote_ip , port))
s.send(name.encode())
# Send data to remote server
print('Connection established with server, your name is: {}'.format(name))
while True:
buffer = input("{}: ".format(namePY))
buffer += '\0'
s.send(buffer.encode())
if(buffer == "/exit\0"):
s.close()
break
# print('# Receive data from server')
time.sleep(0.1)
reply = s.recv(1024).decode()
replyArray = reply.split('|')
if replyArray[0] == namePY:
pass
else:
print('{}: {}'.format(replyArray[0], replyArray[1]))
【问题讨论】:
-
“检查现有连接”是什么意思?就套接字而言,唯一涉及套接字的系统调用是
socket()、bind()、listen()、connect()和accept()。 -
是啊....你已经有很多失败了,例如'recv(newSocket, buffer, 1024, 0);' - 您必须正确且完整地处理从 send()、recv() 等系统调用返回的结果。如果 C 库函数需要 NUL 终止的 char 数组,则必须确保此类参数保证为 NUL 终止。
-
您应该首先阅读有关 TCP/IP 的更多信息。您应该为传入的客户使用多线程 - 查看接受并为每个 Client-Com 提供一个线程。来自接受存储的套接字以列表或类似形式存储。现在您可以遍历列表中的所有套接字并发送/接收消息。您还需要对服务器和客户端进行更多的异常处理:客户端断开连接、服务器关闭套接字等等。
-
即使服务器实现在 PYTHON 中:您也可以将其适配为 C:stackoverflow.com/questions/10810249/… 完成此操作后,我们可以讨论您要发送/接收的数据