【问题标题】:Capital ÅÄÖ not printing correctly大写 ÅÄÖ 未正确打印
【发布时间】:2016-07-11 15:58:42
【问题描述】:

我在尝试让 UTF-8 和瑞典语字符 ÅÄÖ 在 UNIX-talk 克隆中正确打印时遇到的问题感到困惑。

我已经使用 setLocale() 将语言环境设置为 sv_SE,并且我正在使用宽字符来尝试正确显示字符,小写 åäö 工作得很好,但不知何故大写变体不起作用。

下面是完整的代码,我怀疑 reader() sender() 或 putch() 中的字符大小缺少一些东西。

#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ncurses.h>
#include <pthread.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sched.h>
#include <pthread.h>
#include <locale.h>
#include <wchar.h>
#define MATRIXSIZE 1000
#define STACKSIZE 10000
#define CHATLEN 2048

#include <syslog.h>

int r = 0, i = 0, mode = -1;
wchar_t mybuf[CHATLEN], tmbuf[CHATLEN];

WINDOW *me;
WINDOW *them;

struct stuff {
    unsigned int col, row, size, realsize;
    pid_t childpid;
    pid_t mainpid;
    char matrix[MATRIXSIZE];
    char nukeline[1024];
    int nukesize;
    int terminate;
    struct massaskit {
        int writechan;
        int readchan;
        int sockfd;
        struct sockaddr_in server;
        struct sockaddr_in writeclient;
        struct sockaddr_in readclient;
        int c;
        struct hostent *serverhost;
        char hostname[256];
        uint16_t port;
    } bertil;
};

pthread_mutex_t scr_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t sendthread;  // Thread that listens to user's typing, and
                       //    puts the characters on the screen, and
                       //    transmits them over the network.

pthread_t readthread;  // Thread that reads characters from the network
                       //    and shows them on the screen.

int srv1(void *ptr)
{
    struct massaskit *sockstuff = (struct massaskit *)ptr;
    int opt = 1;

    if ((sockstuff->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket();");
        exit(-1);
    }

    sockstuff->server.sin_family = AF_INET;
    sockstuff->server.sin_addr.s_addr = INADDR_ANY;
    sockstuff->server.sin_port = htons(sockstuff->port);
    setsockopt(sockstuff->sockfd, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if (bind
        (sockstuff->sockfd, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) < 0) {
        perror("bind failed");
        exit(-1);
    }

    if ((listen(sockstuff->sockfd, 3)) < 0)
    {
        perror("listen");
        exit(-1);
    }

    sockstuff->c = sizeof(struct sockaddr_in);
    printf("waiting for readchan on %i sockstuff->port..\n",
           sockstuff->port);
    sockstuff->readchan =
        accept(sockstuff->sockfd,
           (struct sockaddr *)&sockstuff->readclient,
           (socklen_t *) & sockstuff->c);

    printf("got a connection! now need a connection on writechan (p:%i)\n",
           sockstuff->port);

    sockstuff->writechan =
        accept(sockstuff->sockfd,
           (struct sockaddr *)&sockstuff->writeclient,
           (socklen_t *) & sockstuff->c);

    printf("got a connection! both read/write  (p:%i)\n", sockstuff->port);
    shutdown(sockstuff->writechan, SHUT_RD);
    shutdown(sockstuff->readchan, SHUT_WR);

    if (close(sockstuff->sockfd) != 0)
    {
        exit(1);
    }

    return 0;
}

int cli1(void *ptr)
{
    /* srv1 starts with readchan, we start with writechan :-) */
    struct massaskit *sockstuff = (struct massaskit *)ptr;
    int opt = 1;
    sockstuff->sockfd = -1; /* make it broken so other function understand */
    if ((sockstuff->writechan = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("writechan->socket()");
        exit(-1);
    }
    else
    {
        printf("socket init is ok.got fd[%i] [writechan]\n",
               sockstuff->writechan);
    }

    setsockopt(sockstuff->writechan, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if ((sockstuff->serverhost =
         gethostbyname(sockstuff->hostname)) == NULL) {
        perror("error in resolving hostname :/\n");
        exit(-1);
    }
    else
    {
        printf("ok, resolved host, now making connection [writechan]!\n");
    }

    memset(&sockstuff->server, '\0', sizeof(struct in_addr));
    sockstuff->server.sin_family = AF_INET;
    memcpy(&sockstuff->server.sin_addr.s_addr,
           sockstuff->serverhost->h_addr,
           (size_t) sockstuff->serverhost->h_length);
    sockstuff->server.sin_port = htons(sockstuff->port);

    if (connect
        (sockstuff->writechan, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) == -1) {
        perror("connection");
        exit(-1);
    }
    else
    {
        printf("%s%s", "writechan established,starting readchan and", "sleeping 2s so other end can initalize the readchan.\n");
    }
    if ((sockstuff->readchan = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket();");
        exit(-1);
    }
    else
    {
        printf("readchan socket init ok.\n");
        fflush(stdout);
    }

    setsockopt(sockstuff->readchan, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if ((sockstuff->serverhost = gethostbyname(sockstuff->hostname)) == NULL)
    {
        perror("error in recieve channel, could'nt resolve host bailing.\n");
        exit(-1);
    }
    else
    {
        printf("readchan could resolve host nice shit alabama\n");
        fflush(stdout);
    }

    memset(&sockstuff->server, '\0', sizeof(struct in_addr));
    sockstuff->server.sin_family = AF_INET;
    memcpy(&sockstuff->server.sin_addr.s_addr,
           sockstuff->serverhost->h_addr,
           (size_t) sockstuff->serverhost->h_length);

    sockstuff->server.sin_port = htons(sockstuff->port);
    if (connect
        (sockstuff->readchan, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) == -1) {
        perror("connect()");
        exit(-1);
    }
    else
    {
        printf("read chan estabiled. starting program!\n");
        fflush(stdout);
    }

    return 0;
}

void putch(WINDOW * win, wchar_t ch)
{
    syslog(LOG_INFO, "%04x", ch);
    if (ch == 4 || ch == 7) // Translate left-arrow, backspace to CTL-H
        ch = '\b';
    if(ch < ' ' && ch != '\t' &&
        ch != '\n' && ch != '\b'
    )
    {
        return;
    }

    pthread_mutex_lock(&scr_mutex);  // Get exclusive access to screen.
    wechochar(win, ch);

    if (ch == '\b')
    {
        wdelch(win);
        refresh();
    }

    pthread_mutex_unlock(&scr_mutex);
}

void setupscreen()
{
    int rows, cols;
    initscr();
    cbreak();
    noecho();
    intrflush(stdscr, FALSE);
    rows = (LINES - 3) / 2;
    cols = COLS - 2;
    me = newwin(rows, cols, 1, 1);
    them = newwin(rows, cols, rows + 2, 1);
    idlok(me, TRUE);
    scrollok(me, TRUE);
    keypad(me, TRUE);
    idlok(them, TRUE);
    scrollok(them, TRUE);
    border(0, 0, 0, 0, 0, 0, 0, 0);
    move(rows + 1, 1);
    hline(0, cols);
    refresh();
}

void* sender(void *ptr) {
    struct stuff *s = (struct stuff *)ptr;
    setupscreen();

    int ch;
    while (1)
    {
        if (i > CHATLEN - 1)
        {
            i = 0;
        }

        ch = wgetch(me);
        mybuf[i] = ch;
        if (ch == KEY_RESIZE)
        {
            clear();
            endwin();
            setupscreen();
            wchar_t *p = &mybuf[0];
            while (&(*p) < &mybuf[CHATLEN - 1])
            {
                putch(me, (*p));
                p++;
            }

            p = &tmbuf[0];
            while (&(*p) < &tmbuf[CHATLEN - 1])
            {
                putch(them, (*p));
                p++;
            }

            refresh();
        }
        else
        {
            putch(me, mybuf[i]);
            int writefd = s->bertil.writechan;
            write(writefd, &mybuf[i], sizeof(mybuf[i]));
        }
            i++;
    }
    pthread_cancel(sendthread);
    return NULL;
}

void* reader(void *ptr) {
    struct stuff *s = (struct stuff *)ptr;
    int ch;

    while(1)
    {
        if(r> CHATLEN - 1)
        {
            r = 0;
        }

        int readfd=s->bertil.readchan;
        if((read(readfd,&ch,sizeof(ch))) == 0)
        {
            endwin();
            refresh();
            return 0;
        }

        tmbuf[r] = ch;
        putch(them, tmbuf[r]);
        r++;
    }
        pthread_cancel(readthread);
        return NULL;
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "sv_SE");
    memset(mybuf, 0, CHATLEN);
    memset(tmbuf, 0, CHATLEN);

    struct stuff s;
    memset(&s, 0, sizeof(struct stuff));

    if (argc == 1)
    {
        printf("usage %s port        [host server on port]\n", argv[0]);
        printf("usage %s port host   [connecto  host:port]\n", argv[0]);
        exit(1);
    }
    else if (argc == 3)
    {
        s.bertil.port = (uint16_t) atoi(argv[1]);
        memset(s.bertil.hostname, 0, 256);
        memcpy(s.bertil.hostname, argv[2], strlen(argv[2]));
        cli1(&s.bertil);
    }
    else if (argc == 2)
    {
        s.bertil.port = (uint16_t) atoi(argv[1]);
        srv1(&s.bertil);
    }

    pthread_create(&readthread, NULL, reader, &s);  
    pthread_create(&sendthread, NULL, sender, &s);  
    pthread_join(sendthread, NULL);
    pthread_join(readthread,NULL);  
}

如果你想试试这个程序,编译如下:

gcc 文件.c -lpthread -lncurses

服务:

./a.out 1234

连接:

./a.out 1234 本地主机

任何帮助将不胜感激!

【问题讨论】:

  • ÅÄÖ 会发生什么?
  • 您的程序在我的环境中运行良好。你能提供你的环境变量LC_TYPELC_ALL吗?
  • 您不应该调用 setlocale(LC_ALL, "sv_SE"); - 相反,您应该调用 setlocale(LC_ALL, ""); 从环境中获取语言环境。
  • Å = �~E Ä = �~D Ö= �~V 是它们在终端中的打印方式,至于我的环境变量。 LC_CTYPE=sv_SE.UTF-8 , LC_ALL 未设置。

标签: c character-encoding pthreads ncurses


【解决方案1】:

其实wchar_t的位数就够了,不太可能出现符号扩展问题。

但是,在两个线程(senderreader)中使用 ncurses 的应用程序,除非您专门编译它并允许使用互斥锁,否则它不会正常工作。 ncurses(就像任​​何curses的实现一样)使用全局变量来维护屏幕。多个线程会以意想不到的方式使用库。

进一步阅读:

【讨论】:

    【解决方案2】:

    尝试在您的函数中使用unsigned char 而不是int

    简单地说,你不需要wchar_tunsigned char(一个字节)在UTF-8(http://www.science.co.il/language/Character-code.asp?s=1252)中就可以了。

    【讨论】:

    • 删除了宽字符并用无符号字符替换了 reader 和 sender 中的整数,仍然大写 ÅÄÖ 不起作用,但我现在至少可以使用小写 åäö 来处理无符号字符。
    • 您是否还从缓冲区和相关函数中替换了 wchar_t ?
    猜你喜欢
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 2012-10-04
    • 2015-11-23
    • 2017-10-09
    相关资源
    最近更新 更多