【发布时间】: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