Cách xây dựng server_relay.c và client.c để nhắn tin như Yahoo chat bằng C?
Mình cần viết hai file là client.c
và server_relay.c
hay client.java
và server_relay.java
có nghĩa là như vầy:
Tin nhắn từ client(1)
gửi đến server_relay
(hiện tin nhắn) và truyền đến client(2)
và ngược lại như sau
client (1) <==> server_relay <==> client (2)
(chỉ có 1 file client.c)
client(1) > hi
server_relay :>hi
client (2): < hi
---
client(2) : < hi
: > hello
server_relay : > hi
: < hello
client (1): < hi
: < hello
cơ bản là nó hoạt động như thế
Khi mình chạy file client.c
và server_relay.c
trên terminal của linux, tin nhắn của client (1)
đi qua và hiện lên trên server_relay
và hiện trên client (2)
và ngược lại (giống như yahoo chat vậy)
Dựa vào cái đề mình đã viết được file proxy nhưng mình cần file này vùa có chức năng server và proxy để tạo thành file server_relay
Mình để file C mình đã viết và đề bài trong file zip bạn nào coi hộ mình với và giúp mình với, đây là link file của mình http://ge.tt/9RNrtNO2/v/0?c3
Code hiện có:
client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port
", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host
");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s
",buffer);
close(sockfd);
return 0;
}
##proxy.c
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
//error function as uses lots
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
//declarations
int sockfd, newsockfd, sendsockfd, serv_portno, cli_portno, n;
struct sockaddr_in serv_addr, host_addr, cli_addr;
socklen_t clilen;
struct hostent *host;
char buffer[65556];
if (argc < 4) {
fprintf(stderr,"usage %s hostname serverport hostport
", argv[0]);
exit(0);
}
serv_portno = atoi(argv[3]);
cli_portno = atoi(argv[2]);
//creating socket for server to accept connections
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
//creating socket for client component to send on
sendsockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sendsockfd < 0) error("ERROR opening socket");
//setting up the server component of the proxy
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; //set address family for address (must be IPV4 as defined by AF_INET)
serv_addr.sin_addr.s_addr = INADDR_ANY; //gets ip address of server
serv_addr.sin_port = htons(serv_portno); //assign port number after ensuring it is big-endian
//set up client part of proxy
host = gethostbyname(argv[1]);
if (host == NULL) {
fprintf(stderr,"ERROR, no such host
");
exit(0);
}
bzero((char *) &host_addr, sizeof(host_addr));
host_addr.sin_family = AF_INET;
bcopy((char *)host->h_addr, (char *)&host_addr.sin_addr.s_addr,host->h_length);
host_addr.sin_port = htons(cli_portno);
if (connect(sendsockfd,(struct sockaddr *) &host_addr,sizeof(host_addr)) < 0)
error("ERROR connecting");
//bind socket to defined address and port, throw error if binding fails.
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR on binding");
//listen for connection requests, 5 defines max quantity of connections waiting to be processed.
listen(sockfd,5);
clilen = sizeof(cli_addr);
//accept a new socket (accept is a blocking call, thus will wait for client connection to be established)
while(1){
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
//throw error if accept returns negative
if (newsockfd < 0)
error("ERROR on accept");
//set the buffer to zero
bzero(buffer,256);
//read from the new socket fd into the buffer
n = read(newsockfd,buffer,255);
//if n is negative error is thrown
if (n < 0) error("ERROR reading from socket");
//display message
printf("Here is the message: %s
",buffer);
//write message to next host
n = write(sendsockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
//send ack of correct message delivery
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
//close sockets to free up file descriptor table.
close(newsockfd);
}
close(sockfd);
return 0;
}
##server2.c
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[1600];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided
");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
while(argc = 0)
{
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,1600);
n = read(newsockfd,buffer,1600);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s
",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
}
close(newsockfd);
close(sockfd);
return 0;
}
Bài này có thể viết bằng java nhưng mình không biết về java bên computer networking
Mình xin càm ơn mọi người trong diễn đàn nhiều lắm
Bạn viết như thế này có nghĩa là gì?
file proxy mục đích để làm gì?
Làm sao để test chương trình của bạn? Build như thế nào? chạy file nào trước file nào sau, step để test? Lỗi đang gặp phải là gì?
proxy.c chính là file file trung gian giữa client và server giống như giám sát viên vậy. ví dụ mình đăng comment lên vnexpress và nó hiện ra lời bình của bạn đang được xem xét nếu ok thì nó chuyển comment lên server (trường hơp này thì tự động)
trong bài mình cần kết hợp cả file server.c và proxy.c lại và tạo thành server_relay
khi chạy chương trình trên terminal của linux, mình cẩn 3 bảng terminal
1 bảng cho server_relay và mã lênh là : ./server_relay port (ví dụ là ./server_relay 12345) là server chạy đầu tiên
2 bảng cho file client.c cả hai bảng có mã lệnh là ./client hostname port (ví dụ là : ./client 192.168.1.17 12345) là file chạy thứ hai và ba để kết nói với server_relay
khi file client.c chay thì nó sẽ hiện lên:
và cách thức hoạt động như trên đó bạn
chỉ có 1 file client.c có nghĩa là code 1 file clientc và nó đóng vai trò là client(1) và client(2) đang trỏ chuyện với nhau thông qua trung gian server_relay và tin nhắn của cà hai client hiện lên trên server_relay
mình mới học computer networking và C nên không hiểu nhiều nên mình không biết viết file server_relay.c
và lỗi hiện nay mình gặp là file client.c của mình chỉ có thể gửi 1 message và sau đó nó ngắt kết nối với file proxy.c
Ok, để mình compile chạy thử
Chạy trên cùng một máy là được?
Update:
Compile server nhưng chạy thì không hiển thị gì cả
Kiểm tra process đang chạy cũng không thấy
Chạy thử client thì bị lỗi
Mình làm sai bước nào?
command gcc sai rồi bạn
gcc -o server2 server2.c như vậy mới đúng
còn client.c không bị lỗi “ERROR connecting: Connection refused” câu này là do mình add vào
khi server.c không hoạt động thì đương nhiên khi đó client.c không thể kết nối thì mới hiện câu đó
./client 192.168.88.11 12345 câu này
192.168.88.11 cái này mình không biết
thường là ví dụ là vậy 192.168.1.11
bạn có thể kiểm tra hostname bằng command /sbin/ifconfig -a
gcc -o server2 server2.c
haygcc server2.c -o server2
đều là một,-o
dùng để chỉ định tên file output. Đặt-o
trước hay sau tên file.c
không thành vấn đề.Dĩ nhiên mình biết điều đó, mình đang muốn nói là server không chạy
Máy mình ip 192.168.88.11
à mình tìm ra lỗi trong server2.c rồi đó là đoạn
while (argc = 0)
bạn sữa lại thành là argc > 0 là ok
OK, đã chạy được.
Là bởi vì bạn gọi
close(sockfd);
ngay sau khiwrite(sockfd,buffer,strlen(buffer));
. Gửi xong gói đầu thì tiênclose
và kết thúc chương trình rồi.Nếu muốn giữ kết nối thì bạn phải dùng vòng lặp như
while
và khôngclose
cho tới khi xong việc(tức khi muốn thoát)Trong code của server có đoạn này để lặp chờ tin từ client
mình thữ rồi bạn và nó hiện kết qua như thế này
enter message : hi
i got message
enter message : hello
(mất câu i got measage và không hiển thị tiếp theo trên server2.c message)
Bạn phải đưa sự thay đổi của bạn lên chứ?
Đây nè bạn
Sửa lại thế này xem
wow hot hoat động rồi vậy lỗi nằm ở chỗ nào vậy bạn
mình đã kiểm tra và chỉ cần 1 file clien.c thì sẽ chay được nhiều client trên terminal và tất cả đều truyền đến server.c với cùng port, bạn bạn cho mình hỏi là làm thế nào để client(1) nhận được
tin nhắn từ những client khác và ngược lại một cách chính xác,
ý tưởng của mình là tạo ra một function server ngay trên chính client và server.c sẽ giữ thêm chức năng chuyển tin nhắn của proxy.c nhưng làm thế nào vậy bạn
Mình không giữ được connection nên cho tạo lại connection cho mỗi message, bạn đọc code sẽ thấy.
vậy lỗi là ở chổ do connect nằm ngoài loop nên nó không lặp lại kết nối hả bạn
Cho mình hỏi, mỗi lần gửi message mà tạo connection hoài thì có bị tràn bộ nhớ hay không.
Có cần phải close connection lại không ? hay hệ thống tự làm.
Đúng rồi.
Tràn bộ nhớ tùy thuộc vào mỗi connection mình có cấp vùng nhớ hay không. Nhưng riêng mỗi connection được tạo ra mà không close thì để lâu sẽ dẫn đến hết file descriptor. Số lượng file descriptor tuy rất lớn nhưng có giới hạn. Mình có thể xem số lượng ở đây
Máy debian mình đang dùng là
813549
, còn trên embedded board mình đang dùng là12601
. Ngoài ứng dụng của mình ra thì còn có nhiều ứng dụng khác cũng sử dụng file descriptor nữa. Đóng mở file là sử dụng thôi.Có, mình phải close.
Bởi vì mỗi khi có một connect từ client, hàm accept sẽ tạo ra một file descriptor nữa. Trong trường hợp này nó là
newsockfd
, có lẽ là viết tắt của new socket file descriptor. Trên server sẽ trả lời thông qua socket này.Code hiện tại chỉ cho phép client tạo socket và write lên đó, sau đó đọc trả lời từ server rồi hủy, không giữ connection.
Để forward được message thì có 3 cách
Cách 1: cho client listen giống như server – phiền, không cần thiết
Cách 2: giữ connection với server để server có thể gửi tin ngược trở lại bất cứ lúc nào? – khá ổn, chỉ có điều là phải code lại để giữ connection
Cách 3: lâu lâu gửi lại lên server hỏi xem tao có nhận được tin nhắn gì không? – dễ nhất, sửa lại implementation hiện tại, thêm cái nick_name nữa là được.
cách 3 thì nó không với yêu cầu đề bài lắm, còn cách 1 như bạn nói
vậy nên chỉ còn cách hai là hợp lý, nhưng có điều là không phải gửi tin ngược trở lại mà là gửi tới một client đang chạy trên một termial khác, ngoài ra mình nghĩ không nhất thiết phải giữ connect với server vì hai file hoat động như thế này
nên mình nghĩ là chỉ cần khi nhập tin nhắn từ 1 client thì nó sẽ truyền qua server và đi đến một clien khác và kết thúc 1 vòng loop vì 1 file clien.c thì chay được nhiều client trên terminal và tất cả đều truyền đến server.c với cùng port
bạn giúp mình code đoạn này được không
Nếu mình rảnh thì mình có thể code toàn bộ bài này, nhưng mình khá bận mình chỉ có thể xem code của bạn rồi hướng dẫn sửa lại cho phù hợp thôi. Chứ còn code hết cả bài thì vừa mất thời gian mà bạn cũng không học được, bạn đang học đúng không?
À tiện đây cũng nhắc bạn luôn là bạn đừng tạo nhiều topic với cùng nội dung, hệ thống sẽ đánh giá bạn là spam và ẩn bài của bạn đấy. Nếu mình rảnh thì mình sẽ xem, còn nếu mình bận thì chắc nhờ các bạn khác vậy.
không, mình hoc chuyên về ứng dụng java và lập trinh web, tự nhiên đâu ra môn này là môn bắt buộc hoc, trong khi mình chả có tí kiến thức gì về C cả, đống kia là mình mò 24/7 tuần trước mới viết được, toàn tiếng anh không :’(
mình chỉ là không biết code phần gửi tin nhăn từ server đến client(2) thui sao cho chính xác nò toan gửi ngược lai client(1)
:’(