- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现多客户端聊天,使用基于 TCP 套接字的连接和线程来管理客户端和输入。但是,发送或接收的字符串的读写没有正确执行,我不太明白为什么。
服务器:
#define IP "127.0.0.1"
#define PORT 9000
#define MAX_CONNECTION_Q 10
#define CLIENTS 10
#define BUFFSIZE 1024
#define NAMELEN 32
#define COMMANDS 16
#define MESSAGESIZE 256
#define LINENUM 512
struct chat{
char userlist[CLIENTS][NAMELEN];
char admin[NAMELEN];
char ID[NAMELEN];
char logg[512][216];
struct chat *next;
int pos;
};
struct client_info{
pthread_t client_ID;
int sockfd;
struct chat chats;
char user[NAMELEN];
struct client_info *next;
};
struct header{
struct client_info *fnode, *lnode;
}*client_head;
struct chat_head{
struct chat *fnode,*lnode;
}*chat_head;
int sockfd, clinfo;
struct client_info thread_info[CLIENTS];
struct header client_list;
pthread_mutex_t mutex;
void list_init() {
client_head = malloc(sizeof(struct header));
chat_head = malloc(sizeof(struct chat_head));
client_head->fnode = NULL;
chat_head->fnode = NULL;
}
int compare(int a, int b){
return (a-b);
}
void chat_insert(struct chat *node){
if(chat_head->fnode == NULL){
chat_head->fnode = node;
chat_head->lnode = node;
}
else{
chat_head->lnode->next = node;
chat_head->lnode = node;
}
}
int search_cli(char *name){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
if(strcmp(tmp->user,name) == 0){
return tmp->sockfd;
}
tmp = tmp->next;
}
return -1;
}
void client_insert(struct client_info *node){
if(client_head->fnode == NULL){
client_head->fnode = node;
client_head->lnode = node;
node->next = NULL;
}
else{
client_head->lnode->next = node;
client_head->lnode = node;
node->next = NULL;
}
}
void client_delete(struct client_info *node){
struct client_info *last = client_head->fnode;
struct client_info *tmp = last->next;
if(client_head->fnode == NULL){
return;
}
if(compare(last->sockfd, node->sockfd) == 0){
client_head->fnode = tmp;
free(last);
if(client_head->fnode == NULL){
client_head->lnode = NULL;
}
return;
}
while(tmp!=NULL){
if(compare(tmp->sockfd, node->sockfd) == 0) {
last->next = tmp->next;
free(tmp);
return;
}
tmp = tmp->next;
}
}
void display_clients(){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
printf("Username: %s\nSocket: %d\n--------------------\n",tmp->user,tmp->sockfd);
tmp = tmp->next;
}
}
void change_username(int sock,char *sender){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
if(tmp->sockfd == sock){
strcpy(tmp->user,sender);
break;
}
tmp = tmp->next;
}
}
void *client_commands_handler(void *fd){
struct client_info *clinfo = (struct client_info *)fd;
char *buffer = malloc(NAMELEN);
char receiver[NAMELEN],sender[NAMELEN],message[BUFFSIZE];
recv(clinfo->sockfd,buffer,NAMELEN,0);
strcpy(clinfo->user,buffer);
memset(buffer,0,sizeof(buffer));
int nbytes;
while(1){
memset(buffer,0,sizeof(buffer));
nbytes = recv(clinfo->sockfd, buffer, BUFFSIZE, 0);
if(nbytes<=0) {
printf("%s lost connection\n", clinfo->user);
pthread_mutex_lock(&mutex);
client_delete(clinfo);
pthread_mutex_unlock(&mutex);
break;
}
printf("%s\n",buffer);
else if(strncmp(buffer, "private", 7) == 0) {
int sockid;
sscanf(buffer,"private %s %s %s",sender,receiver,message);
printf("%s%s%s",sender,receiver,message);
if((sockid = search_cli(sender)) == -1){
char *server = malloc(NAMELEN);
strcpy(server,"<Server> User doesn't exist\n");
write(clinfo->sockfd,server,strlen(server));
}
else{
struct chat new_chat;
new_chat.pos = 0;
strcpy(new_chat.logg[new_chat.pos],message);
new_chat.pos++;
strcpy(new_chat.userlist[0],sender);
strcpy(new_chat.userlist[1],receiver);
sprintf(new_chat.ID,"%s%s",new_chat.userlist[0],new_chat.userlist[1]);
new_chat.next = NULL;
pthread_mutex_lock(&mutex);
chat_insert(&new_chat);
pthread_mutex_unlock(&mutex);
send(sockid,message,strlen(message),0);
}
}
else {
fprintf(stderr, "Garbage data from [%d] %s...\n", clinfo->sockfd, clinfo->user);
}
}
close(clinfo->sockfd);
return NULL;
}
void *server_commands_handler() {
}
int main() {
int size,clientfd;
struct sockaddr_in server_addr, client_addr;
pthread_t server_commands;
list_init();
pthread_mutex_init(&mutex, NULL);
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Couldn't get server socket");
exit(0);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(IP);
memset(&(server_addr.sin_zero), 0, 8);
if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
perror("Couldn't bind socket");
exit(0);
}
if(listen(sockfd, MAX_CONNECTION_Q) == -1){
perror("Couldn't listen");
exit(0);
}
if(pthread_create(&server_commands, NULL, *server_commands_handler, NULL) != 0){
perror("Couldn't create thread");
exit(0);
}
while(1){
size = sizeof(struct sockaddr_in);
if((clientfd = accept(sockfd, (struct sockaddr *)&client_addr,(socklen_t*)&size))==-1){
perror("Connection failed");
exit(0);
}
printf("Client accepted\n");
struct client_info clinfo;
clinfo.sockfd = clientfd;
clinfo.next = NULL;
pthread_mutex_lock(&mutex);
client_insert(&clinfo);
pthread_mutex_unlock(&mutex);
pthread_create(&clinfo.client_ID, NULL, client_commands_handler, (void *)&clinfo);
}
return 0;
}
客户:
#define SERVERIP "127.0.0.1"
#define SERVERPORT 9000
#define BUFFSIZE 1024
#define USERLEN 32
#define OPTLEN 16
struct threadinfo{
pthread_t thread_ID;
int sockfd;
};
struct USER{
char user[USERLEN];
int sockfd;
char current_convo[USERLEN];
};
int isconnected, sockfd, sent;
char option[BUFFSIZE];
struct USER me;
int connect_with_server();
void logout(struct USER *me);
void login(struct USER *me);
void *receiver();
void login(struct USER *me){
if(isconnected){
printf("Already connected\n");
return;
}
sockfd = connect_with_server();
if(sockfd == -1){
perror("Couldn't connect to server\n");
}
if(sockfd >= 0) {
isconnected = 1;
me->sockfd = sockfd;
printf("Logged in as %s\n", me->user);
struct threadinfo thread;
pthread_create(&thread.thread_ID, NULL, receiver, (void *)&thread);
}
else {
printf("Couldn't connect.\n");
exit(0);
}
}
void *receiver(){
int recvd;
char msg[BUFFSIZE];
while(isconnected){
memset(msg,0,sizeof(msg));
recvd = read(sockfd, msg, sizeof(msg));
if(!recvd) {
printf("Connection Lost from Server\n");
isconnected = 0;
close(sockfd);
break;
}
if(recvd > 0) {
fputs(msg,stdout);
}
}
return NULL;
}
int main() {
memset(&me, 0, sizeof(struct USER));
char msg[BUFFSIZE];
char *token;
while(fgets(option,BUFFSIZE-1,stdin)){
memset(msg,0,sizeof(msg));
if(strncmp(option,"exit", 4) == 0){
logout(&me);
break;
}
else if(strncmp(option, "login", 5) == 0){
token = strtok(option, " ");
token = strtok(NULL, "\n");
memset(me.user, 0, sizeof(char)*USERLEN);
if(token != NULL) {
strcpy(me.user, token);
login(&me);
}
else{
printf("Couldn't get valid username\n");
}
}
else if(strncmp(option, "private", 7) == 0){
if(isconnected == 0){
printf("User not connected\n");
}
else{
char *tmp = malloc(USERLEN);
token = strtok(option, " ");
token = strtok(NULL, " ");
strcpy(tmp,token);
token = strtok(NULL, "\n");
sprintf(msg,"private %s %s %s",me.user,tmp,token);
send(sockfd, msg, strlen(msg),0);
}
}
return 0;
}
该代码有很多代码对于简单的基于双向输入的连接来说是不必要的,但是从长远来看,我正在尝试实现它,它将具有更多功能。这里有很多事情需要修复,但我的问题是主要侧重于通过“私有(private)”输入发送字符串,应如下所示:
private (username of receiver) (message to send)
最佳答案
我还在看它,但我注意到了一些事情。在您的服务器中,您有
char *buffer = malloc(NAMELEN);
char receiver[NAMELEN],sender[NAMELEN],message[BUFFSIZE];
recv(clinfo->sockfd,buffer,NAMELEN,0);
strcpy(clinfo->user,buffer);
memset(buffer,0,sizeof(buffer));
int nbytes;
while(1){
memset(buffer,0,sizeof(buffer));
nbytes = recv(clinfo->sockfd, buffer, BUFFSIZE, 0);
缓冲区变量接收指向 NAMELEN (32) 字节 block 的指针。您无需查看状态即可接收 NAMELEN 字节。到目前为止,一切都很好。然后清除缓冲区的第一个 sizeof 字节(由于缓冲区是一个指针,因此您将清除 4 或 8 个字节)。不久之后,您将 BUFFSIZE (1024) 字节接收到可怜的 32 字节缓冲区中。
我建议您通过 telnet 测试来运行服务器
telnet 127.0.0.1 9000
并输入您的程序所期望的内容。请记住,只有当您按回车键时才会传输数据。
客户端可以通过 netcat 进行类似的练习:
nc -l 127.0.0.1 9000
当我这样做时,为什么你的客户端是多线程的?如果直接调用receiver()而不是创建另一个线程,事情会变得简单。
还要留意您的 malloc 并确保它们与 free 配对。我看到很多地方都分配了固定大小的内存块,然后不释放它。使用局部变量可以更干净地完成此操作。当你回来时,这些就会消失。或者,查看 alloca(),当您返回时它也会消失。它并非随处可用,但非常有用。
关于c - c 中的 TCP 聊天无法正确读取/发送字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47688791/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!