【问题标题】:Socket Programming C [Sending message to selected client]Socket Programming C [向选定的客户端发送消息]
【发布时间】:2017-10-30 10:33:58
【问题描述】:

我一直在尝试用 C 编写一个套接字程序。我的目标是尝试做多线程服务器-客户端消息应用程序。所以我可以将多个客户端连接到服务器并从服务器向它们发送消息。

我的代码工作但不是我想要的。例如,如果我运行服务器并且只有一个客户端,它可以向客户端发送消息,但是当我尝试连接另一个客户端时,它会逐步发送消息。例如,如果我在服务器上写一些东西并发送,它首先发送给客户端;如果我写了一些东西并再次发送,它会转到第二个客户端。我需要选择我想发送消息的客户端,但我无法弄清楚。你能帮帮我吗?

这里是它的服务器代码

     #include <windows.h>
     #include <stdio.h>
     #include <conio.h>
     #include <process.h>
     #pragma comment(lib, "Ws2_32.lib")

     char buffer[100];

     int MyFunction(void* Arg)
      {
SOCKET Client = (*(int *)Arg);

while (1)
{   
    //int Socket = (*(int *)Arg);
    printf("-> ");
    gets(buffer);
    send(Client, buffer, 100, 0);   
}

_endthreadex(0);
    }
      /*--------------------------------------------------------------------            */
     void main(void)
     {
int a, b, c, d; 
int port;    
struct sockaddr_in serv_addr, cli_addr;
SOCKET Server;
SOCKET Client;
int clilen = sizeof(cli_addr);


// SOCKET  INITIALISATION
WSADATA WsaDat;
if (WSAStartup(MAKEWORD(1, 1), &WsaDat) != 0)
{
    printf("\n\n WSA Initialization failed!");
    exit(1);
}


// SOCKET
Server = socket(AF_INET, SOCK_STREAM, 0);
if (Server == INVALID_SOCKET)
{
    printf("\n\n Socket creation failed!");
    exit(1);
}
else
    printf("\n\n SOCKET IS CREATED SUCCESSFULLY...");


// SERVER  ADDRESS  
serv_addr.sin_family = AF_INET;
printf("\n ENTER THE SERVER IP ");
scanf_s("%d %d %d %d", &a, &b, &c, &d);
serv_addr.sin_addr.S_un.S_un_b.s_b1 = a;
serv_addr.sin_addr.S_un.S_un_b.s_b2 = b;
serv_addr.sin_addr.S_un.S_un_b.s_b3 = c;
serv_addr.sin_addr.S_un.S_un_b.s_b4 = d;
printf("\n ENTER THE PORT NO ");
scanf_s("%d", &port);
serv_addr.sin_port = htons(port);


// BIND 
if (bind(Server, (struct sockaddr *)(&serv_addr), sizeof(serv_addr)) == SOCKET_ERROR)
{
    printf("\n\n Attempt to bind failed!STOP!!!");
}
else
    printf("\n\n BIND PROCESS IS CREATED SUCCESSFULLY...\n ");


// LISTEN 
if (listen(Server, 5) == SOCKET_ERROR)
    printf("\n Error in Listenning The Socket!\n");

/*---------------------------------------------------*/

int i = 0;
while (1)
{
        printf("\n SERVER IS RUNNING...\n ");

            printf("Client %d is connected!\n", i);



        Client = accept(Server, (struct sockaddr*)&cli_addr, &clilen);

        _beginthread(MyFunction, 0, (void *)&Client);

        i++;
}
_getch();


   }

这是客户端代码:

    #include<stdio.h>
    #include<conio.h> 
    #include<winsock2.h>
    #include<process.h>
    #pragma comment(lib, "Ws2_32.lib")


    char buffer[100];

    void MyFunction(void * Arg)
        {
SOCKET Socket = (*(int *)Arg);
while (1)
{

    recv(Socket, buffer, 100, 0);
    printf("Server: %s\n", buffer);
}
_endthread();
    }

    void main(void)
     {
WSADATA WsaDat;
if (WSAStartup(MAKEWORD(2, 0), &WsaDat) != 0)
{
    printf("\n WSA Initialization failed.");
    exit(1);
}

struct STRUCTADDR
{
    short  sin_family;
    short  sin_port;
    struct in_addr sin_addr;
    char   sin_zero[8];
};

struct STRUCTADDR p1_addr, cli_addr;
int clilen = sizeof(cli_addr);
p1_addr.sin_family = AF_INET;
int a, b, c, d;
printf("\n\n ENTER THE SERVER IP ");
scanf_s("%d %d %d %d", &a, &b, &c, &d);
p1_addr.sin_addr.S_un.S_un_b.s_b1 = a;
p1_addr.sin_addr.S_un.S_un_b.s_b2 = b;
p1_addr.sin_addr.S_un.S_un_b.s_b3 = c;
p1_addr.sin_addr.S_un.S_un_b.s_b4 = d;
int port;
printf("\n\n ENTER THE PORT NO ");
scanf_s("%d", &port);
p1_addr.sin_port = htons(port);

/*--------------------------------------------*/

SOCKET Socket;
Socket = socket(AF_INET, SOCK_STREAM, 0);
if (Socket == INVALID_SOCKET)
{
    printf("\n Socket creation failed.");
    exit(1);
}
printf("\n SOCKET IS CREATED SUCCESSFULLY");
if (connect(Socket, (SOCKADDR *)(&p1_addr), sizeof(p1_addr)) != 0)
{
    printf("\n Failed to establish connection with server...");
}

else
    //while (1)
    //{
        printf("\n\n CONNECTED\n");
        _beginthread(MyFunction, 0, (void *)&Socket);

    //}
_getch();


    }

【问题讨论】:

  • '_beginthread(MyFunction, 0, (void *)&Client);'不。将同一个本地变量的地址传递给所有线程是不安全的。 'recv(Socket, 缓冲区, 100, 0);'未能正确和完整地处理 recv() 返回的结果。 'printf("服务器: %s\n", 缓冲区);'在不能保证 NUL 终止的 char 数组上调用 'printf("%s...'。其他的东西。
  • 你为什么使用线程?您所做的一切都不需要它们,您可以使用select() 来做一个单线程多客户端服务器。
  • 另外,不要使用gets - 它不再是 C 标准的一部分,而且很容易出现缓冲区溢出。
  • 其实我不知道我在做什么。我是套接字编程的新手。我只是想达到我的目标。当然,其中一些可能是错误的或不必要的
  • 当我使用 scanf_s("%s",buffer) 而不是 gets 时,它不起作用

标签: c sockets client-server


【解决方案1】:

当您在服务器中接受套接字时,您需要将接受的套接字添加到队列或数组中,而不是将其直接传递给您的线程函数。 (可选)您还可以存储由 accept() 调用返回的每个对等方的 IP 地址,以便在您想向他们发送数据时识别给定的客户端

【讨论】:

  • 获取所有连接的 cli_addr 值是个好主意,然后我可以在 _beginthread(MyFunction, 0, (void *)&cli_addr);这里。其实我不知道是哪个地址发送消息。