在C客户机/服务器套接字(Client/server sockets in c)

2019-09-28 01:13发布

目前我正在试图了解如何使用套接字来使C.我一直在阅读各种教程围绕互联网,希望尝试做,可以同时处理多个客户端小的反响服务器的客户机/服务器程序。 每当客户端向服务器发送消息,所述服务器被认为是回声回客户端。 我创建的代码都来自于学校的演讲(这解释了如何创建客户端和服务器)的教程的组合,以及一个例子,我发现这里的计算器(这表明如何使实际呼应功能消息)。 我希望有人能有什么我缺少正确地使这个工作方案向我解释。 下面是客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

char buf[80];
struct sockaddr myname;

void replyBack(FILE *fp, int sockfd) {
char sendline[1000], recvline[1000];
printf("Enter your echo: \n");
while(fgets(sendline,1000,stdin) != NULL) {
    write(sockfd,sendline,sizeof(sendline));
    if(read(sockfd,recvline,1000) == 0) {
        printf("str_cli: server terminated prematurely");
        exit(-1);
    }
    fputs(recvline, stdout);
}
}

main() {
int sock, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
    printf("client socket failure%d\n", errno);
    printf("client: ");
    exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);

if(connect(sock, &myname, adrlen) < 0) {
    printf("client connect failure %d\n", errno);
    perror("client: ");
    exit(1);
}

replyBack(stdin,sock);
exit(0);
}

这里是服务器的代码:

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

struct sockaddr myname;
char buf[80];

void echo(int sockfd) {
ssize_t n;
int write_err;
char buf[1000];
char * send_start_pos;
while(1) {
    bytes_in = read(sockfd, buf, 1000);
    if(bytes_in < 1) {
        if(errno == EINTR)
            continue;
        break;
    }
    bytes_remaining = bytes_in;
    send_start_pos = buf;
    write_err = 0;

    while((bytes_remaining > 0) && !(write_err)) {
        bytes_out = write(sockfd, send_start_pos,           
                bytes_remaining);
        if(bytes_out < 0) {
            if(errno == EINTR)
                continue;
            write_err = 1;
            break;
        }
    bytes_remaining -= bytes_out;
    send_start_pos += bytes_out;
    }
    if(write_err)
        break;
}
}

main() {
int sock, new_sd, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
    printf("server socket failure %d\n", errno);
    perror("server: ");
    exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);

unlink("/tmp/billb"); /*defensive programming */
if(bind(sock, &myname, adrlen) < 0) {
    printf("server bind failure%d\n", errno);
    perror("server: ");
    exit(1);
}

if(listen(sock, 5) < 0) {
    printf("server listen failure %d\n", errno);
    perror("server: ");
    exit(1);
}

while(1) {
    if(new_sd = accept(sock, &myname, &adrlen) < 0) {
        printf("server accept failure %d\n", errno);
        perror("server: ");
        exit(1);
    }

    printf("Socket address in server %d is %s, %s\n", 
        getpid(), myname.sa_data, myname.sa_data);

    if(fork() == 0) {
        close(sock);
        echo(new_sd);
        exit(0);
    }
    close(new_sd);
}
}

当我运行程序的问题是,客户端接受消息,但随后并没有真正将其发送到服务器,因此服务器不能呼应回来。

我知道这可能是基本的东西,所以我感谢您的耐心和时间!

Answer 1:

adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family); 

这应该是sizeof myname 。 在unix(7)套接字实际上定义为具有sockaddr_un这样的:

       #define UNIX_PATH_MAX    108

       struct sockaddr_un {
           sa_family_t sun_family;               /* AF_UNIX */
           char        sun_path[UNIX_PATH_MAX];  /* pathname */
       };

你给它10+4的大小。 几乎应该努力-它不计算终止NUL在文件名的最后一个字节-但即使与+ 1加,我会感觉更好,如果你传递你有对象的尺寸完全相同。 (小心的strlen(3)上的字符串。几乎总是需要一个+ 1中涉及的任何表达strlen(3)滑稽。)

 while(fgets(sendline,1000,stdin) != NULL) { write(sockfd,sendline,sizeof(sendline)); 

在这里,您所发送的所有1000个字节的缓冲区,而不管内容。 用户可能输入一个字符,或一百,你要发送的所有1000个字节的无论是在该地址。

您的echo方法有点多; 我建议你关闭分裂书写到自己的日常; 高级编程在Unix环境第二版 (一个极好的书籍,非常值得找到一个副本,如果你希望Unix或类Unix系统程序)有一个小甜例行我真的很喜欢:

 ssize_t /* Write "n" bytes to a descriptor */ writen(int fd, const void *ptr, size_t n) { size_t nleft; ssize_t nwritten; nleft = n; while (nleft > 0) { if ((nwritten = write(fd, ptr, nleft)) < 0) { if (nleft == n) return(-1); /* error, return -1 */ else break; /* error, return amount written so far */ } else if (nwritten == 0) { break; } nleft -= nwritten; ptr += nwritten; } return(n - nleft); /* return >= 0 */ } 

(见lib/writen.c在从本书的网站源 。)

我还没有真正尝试你的代码,所以它是没有这些很可能实际上是防止你的软件从工作:)如果是这样的话,发表评论,我会仔细看看这个问题。



Answer 2:

你错过了包括一卡车。 我花时间来编译您的程序和这种宝石站出来警告的人群

warning: suggest parentheses around assignment used as truth value

在这条线

if(new_sd = accept(sock, &myname, &adrlen) < 0) {

所以基本上你检查是否接受退货东西低于0和分配,要new_sd。 把上面一行

if((new_sd = accept(sock, &myname, &adrlen)) < 0) {

奖励 :最多在他的回答@sarnold说的是正确的,从长远来看,会比我更好的回答你。



文章来源: Client/server sockets in c