OK. Ваш код дал понять, что вы не очень хорошо знаете C, гораздо меньше сокетов, но вот новая улучшенная версия, которая, я думаю, будет делать то, что вы хотите. Большинство моих улучшений были освещены в комментариях к исходной публикации. Я не проверял наличие ошибок везде, где это уместно, и во многих других отношениях это далеко от совершенства, но это будет делать то, что вы хотели, без срывов.
Вы отправляли данные, не зная, получили ли вы все, что было передано. Розетки - это потоки. Он отправляет данные, однако находит это наиболее удобным, а не так, как вы предпочитаете. Чтобы решить эту проблему, я потребовал, чтобы мы отправляли \n
с каждой передачей. Мы проверяем \n
и продолжаем читать данные каждый раз, когда получаем данные с другой стороны. После того, как я отправил множество данных ответа, я отправил один символ \n
, чтобы клиент знал, что была получена полная строка. Нам не нужно добавлять \n
от клиента, так как fgets
оставляет \n
в конце буфера.
Вы упомянули сортировку, так что в качестве дополнительного бонуса я добавил qsort
, чтобы упорядочить данные. В функции compReply
я не просто возвращаю значение непосредственно из strcmp
, но помещаю его в int
, чтобы при необходимости видеть его в отладчике. Я полагаю, что некоторые компиляторы будут жаловаться, что я делаю strcmp
для двух void *
переменных. Чтобы быть аккуратным, вы можете разыграть их с (char*)a
, прежде чем передать их на strcmp
.
Я удалил ваш fork
, чтобы облегчить отладку. Извините, это позволит только одно соединение одновременно. Когда я пишу что-то вроде этого, я обычно не разветвляю новый процесс, а имею массив значений newSocket и использую select
, чтобы решить, с какого из них читать. (Функцию select
можно использовать и с accept
.) Опять же, проще отлаживать таким образом.
Функция strtok
заменяет найденный символ на ноль и возвращает указатель на начало строки. Я просто хотел удалить ненужные символы, поэтому я использовал его, не удосужившись принять возвращаемое значение. Это также можно было бы сделать с чем-то вроде:
char *p=strchr(buffer,'\n');
if( NULL != p ) *p=0;
Но strtok
более лаконичен.
Я разрешил передавать номер порта на сервер, но не смог добавить его к клиенту. Ох, хорошо.
Я проверил сервер до того, как запустил клиент с
telnet 127.0.0.1 4444
и набрал: a,s,d,f,g,h,j,k,l <CR>
чтобы вернуть отсортированный список a,d,f,g,h,j,k,l,s,
Мне также не нравятся конечные запятые, но я не собираюсь сейчас их убирать.
Сервер:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 4444
#define BUF_SIZE 1024
static int compReply(const void *a, const void *b)
{
int ret=strcmp(a,b);
return(ret);
}
int main(int argc, char *argv[])
{
int port=4444;
int sockfd, ret;
struct sockaddr_in serverAddr; // Local address
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
if( argc > 1 ) {
port=atoi(argv[1]);
if( port < 1024 ) {
port=4444;
}
}
// Create socket for incoming connections
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("Error in connection.\n");
exit(1);
}
printf("Server Socket is created.\n");
// Construct local address structure
memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
serverAddr.sin_family = AF_INET; // IPv4 address family
serverAddr.sin_port = htons(PORT); // Local port
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface
// Bind to the local address
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("Error in binding.\n");
perror("bind");
exit(1);
}
printf("Bind to port %d\n", port);
// Mark the socket so it will listen for incoming connections
if(listen(sockfd, 10) == 0){ //Maximum outstanding connection requests is 10
printf("Listening....\n");
}else{
printf("Error in listening.\n");
perror("listen");
}
while(1){
// Wait for clients to connect
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
if(newSocket < 0){
exit(1);
}
// newSocket is connected to client!
char newName[INET_ADDRSTRLEN]; // String to contain client address
if (inet_ntop(AF_INET, &newAddr.sin_addr.s_addr, newName, sizeof(newName)) != NULL)
printf("Handling client %s/ %d\n", newName, ntohs(newAddr.sin_port));
else
printf("Unable to get client address");
while(1){
char buffer[BUF_SIZE]={0};
int ret=1;
int count=0;
while(NULL == strchr(buffer,'\n') && ret > 0 && count < sizeof(buffer))
{
ret=recv(newSocket, &buffer[count], sizeof(buffer)-count, 0);
count+=ret;
}
if( ret <= 0 ) {
if( ret < 0 ) {
printf("Problem with recv: %d\n", ret);
}
break;
}
printf("recv: %s\n", buffer);
strtok(buffer,"\n\r"); /* throw away any \r\n */
if( ret> 0 ) {
int i=0;
char reply[20][BUF_SIZE]={0};
char *p = strtok(buffer, ",");
while (p!=NULL) {
strncpy(reply[i],p,BUF_SIZE);
strcat(reply[i],",");
p = strtok(NULL, ","); //stroke received string into tokens
i++;
}
qsort(reply,i,BUF_SIZE,compReply);
for(int jj=0; jj<i; jj++) {
printf("%s ", reply[jj]);
ret=send(newSocket, reply[jj], strlen(reply[jj]), 0);
}
ret=send(newSocket, "\n", 1, 0);
printf("\n");
}
}
close(newSocket);
}
return 0;
}
Клиент:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define PORT 4444
#define BUF_SIZE 1024
int main(int argc, char *argv[])
{
char servIP[120]="127.0.0.1";
if( argc > 1 ) {
strncpy(servIP,argv[1],sizeof(servIP));
}
int clientSocket, ret;
struct sockaddr_in serverAddr; // Server address
char buffer[BUF_SIZE];
// Create a reliable, stream socket using TCP
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if(clientSocket < 0){
printf("Error in connection.\n");
exit(1);
}
printf("Client Socket is created.\n");
// Construct the server address structure
memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
serverAddr.sin_family = AF_INET; // IPv4 address family
serverAddr.sin_port = htons(PORT); // Server port
// Convert address
int rtnVal = inet_pton(AF_INET, servIP, &serverAddr.sin_addr.s_addr);
if (rtnVal == 0)
printf("inet_pton() failed: invalid address string");
else if (rtnVal < 0)
printf("inet_pton() failed");
// Establish the connection to the sorted server
ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("Error in connection.\n");
exit(1);
}
printf("Connected to Server.\n");
//Read arrays from input file
FILE *fptr;
fptr = fopen("this.csv", "r"); //open input file to read
if (fptr != NULL) {
while(fgets(buffer, sizeof(buffer), fptr)) //read line by line of the input file
{
char reply[BUF_SIZE]={0};
char repList[20][BUF_SIZE]={0};
int count=0;
int ret=1;
printf("Unsorted array: %s", buffer);
// Send array to the server
send(clientSocket, buffer, strlen(buffer), 0);
// Receive the sorted arrays back from the server
while(NULL == strchr(reply,'\n') && ret > 0 && count < sizeof(reply))
{
ret=recv(clientSocket, &reply[count],sizeof(reply)-count,0);
count+=ret;
}
if( ret < 0 ) {
printf("Error in receiving data.\n");
}
else {
int i=0;
strtok(reply,"\n\r");
for(char *p=strtok(reply,",");p!=NULL; p=strtok(NULL,","))
{
strncpy(repList[i],p,BUF_SIZE);
i++;
}
printf("Sorted array:");
for (int jj=0; jj<i; jj++) {
printf("%s ", repList[jj]);
}
}
printf("\n");
}
fclose(fptr);
}
else {
printf("File does not exist");
perror("fopen");
exit(1);
}
return 0;
}
Это должно дать вам кое-что, с чем можно поэкспериментировать. Надеюсь, это поможет.