我编写了一个客户端和服务器c程序,我从示例代码中获取了该程序。
我想写一个迭代的客户端和服务器程序, 即在客户端发送字符串后,服务器打印该字符串,然后将字符串发送回客户端
然后客户端打印服务器输入的字符串,依此类推,直到客户端输入'exit'退出。
我修改了客户端和服务器迭代的代码
另外,如果客户输入'exit',程序将退出
但我有一个问题,我不知道如何让客户端接收服务器输入的字符串,我只能让服务器接收客户端的字符串
请随时提供提示
非常感谢!
我的代码
client.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>
#define SA struct sockaddr
#define S_PORT 4321
#define BufferStoreLEN 1024
void errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);
}
int main(int argc, char **argv)
{
WSADATA wsadata;
SOCKET sockfd, listenfd, connfd;
int i, n, q, len, alen, out;
char str[BufferStoreLEN+1];
char cmp[] = "exit";
char* BufferStore;
struct sockaddr_in servaddr, cliaddr;
if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
errexit("WSAStartup failed\n");
if (argc != 2)
errexit("wrong arg");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
errexit("socket error: error number %d\n", WSAGetLastError());
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(S_PORT);
if ( (servaddr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)
errexit("inet_addr error: error number %d\n", WSAGetLastError());
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
errexit("connect error: error number %d\n", WSAGetLastError());
do {
printf("Input: ");
scanf("%s", str);
out = htonl(strlen(str));
BufferStore = malloc(strlen(str));
for( i=0; i<strlen(str); i++)
BufferStore[i] = str[i];
out = send(sockfd, BufferStore, strlen(str), 0);
/*
if ( strcmp( cmp, str ) != 0 )
{
printf("Server's response:\n");
n = recv(connfd, BufferStore, BufferStoreLEN, 0);
while (n > 0) {
BufferStore[n] = '\0';
printf("%s\n", BufferStore);
n = recv(connfd, BufferStore, BufferStoreLEN, 0);
}
}*/
}while(strcmp(cmp,str)!=0);
closesocket(sockfd);
WSACleanup();
free(str);
free(BufferStore);
return 0;
}
server.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>
#include <Windows.h>
#define SA struct sockaddr
#define MAXLINE 4096
#define S_PORT 4321
#define BufferStoreLEN 1024
void errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);
}
int main(int argc, char **argv)
{
WSADATA wsadata;
SOCKET listenfd, connfd;
SOCKET sockfd;
int number, out;
int i, n, q, alen;
struct sockaddr_in servaddr, cliaddr;
char BufferStore[BufferStoreLEN+1];
char* Store;
char str[BufferStoreLEN+1];
int flag = 1;
if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
errexit("WSAStartup failed\n");
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == INVALID_SOCKET)
errexit("cannot create socket: error number %d\n", WSAGetLastError());
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(S_PORT);
if (bind(listenfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
errexit("can't bind to port %d: error number %d\n", S_PORT, WSAGetLastError());
if (listen(listenfd, 5) == SOCKET_ERROR)
errexit("can't listen on port %d: error number %d\n", S_PORT, WSAGetLastError());
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
errexit("socket error: error number %d\n", WSAGetLastError());
for ( ; ; )
{
alen = sizeof(SA);
connfd = accept(listenfd, (SA *) &cliaddr, &alen);
if (connfd == INVALID_SOCKET)
errexit("accept failed: error number %d\n", WSAGetLastError());
n = recv(connfd, BufferStore, BufferStoreLEN, 0);
while (n > 0){
BufferStore[n] = '\0';
printf("%s\n", BufferStore);
printf("Input: ");
scanf("%s",str);
out = htonl(strlen(str));
Store = malloc(strlen(str));
for( q=0; q<strlen(str); q++)
Store[q] = str[q];
out = send(sockfd, Store, strlen(str), 0);
n = recv(connfd, BufferStore, BufferStoreLEN, 0);
}
closesocket(sockfd);
WSACleanup();
free(str);
free(BufferStore);
}
}
答案 0 :(得分:0)
您的服务器在无限循环内运行,因此为了能够将在服务器应用程序中输入的数据发送到客户端应用程序,您必须在不同的线程中读取用户输入,然后将其发送给用户,因为无限循环当前正在阻塞当前线程。
答案 1 :(得分:0)
了解流套接字(SOCK_STREAM)的一个重要事项是它们为您提供了一个流字节(因此名称为:-)),没有任何“数据包边界”。
具体来说,如果从客户端发送()100字节的数据,服务器可能会将其作为
重新发送()您的代码似乎假设您在一端发送的()将在另一端的单个recv()调用中传递。对于小块数据,这可能有用,但它不是你可以/应该依赖的东西。
一般来说,要像你正在设置一样执行命令/响应场景,你需要让服务器识别“这是命令的结束,我现在应该回应”。例如,如果您要发送文本字符串,则可以使用换行符(\ n)作为“命令结束”标记。
服务器因此会执行多个recv()调用(每个调用附加到缓冲区),直到它看到\ n(或错误),然后发回响应;在阅读回复时,客户会做类似的事情。