2011-04-26 128 views
1

我剛開始學習socket編程,發現它很有趣。 目前,我正在服務器和客戶端在同一臺計算機上,因此我可以有IP地址作爲環回地址,127.0.0.1和一切似乎工作正常!初學者的Socket編程C

但現在我正在考慮有兩臺電腦,做這件事.. 我有以下問題 - 1)說一臺電腦是服務器,另一臺是客戶端。現在,如果服務器代碼駐留在服務器計算機上並且客戶端上的客戶端代碼是? 2)在我們爲bind()提供ip地址的服務器代碼中,它應該是我們可以通過ipconfig找到的系統的ip地址,或者它應該仍然是回送地址? 3)在客戶端代碼中,我猜目的地的IP地址應該是服務器計算機的IP地址? 4)最後也是最重要的事情,我如何連接兩臺計算機?

我附加了我開始使用的簡單服務器和客戶端消息傳遞代碼。請指導我,我需要進行更改..

服務器代碼

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <string.h> 

#define MYPORT 3500 

int main() 
{ 
    int sockfd; 
    int clientfd; 
    int bytes_read; 
    char buf[100]; 
    int struct_size; 
    struct sockaddr_in my_addr; 
    struct sockaddr_in con_addr; 

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    my_addr.sin_family = AF_INET; 
    my_addr.sin_port = htons(MYPORT); 
    my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    my_addr.sin_zero[8]='\0'; 

    bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)); 

    listen(sockfd,5); 

    struct_size = sizeof(con_addr); 
    clientfd = accept(sockfd, (struct sockaddr*)&con_addr, &struct_size); 

    bytes_read = read(clientfd, buf, 100); 
    buf[bytes_read] = '\0'; 
    printf("Message from client:%d is %s \n",clientfd, buf); 

    close(sockfd); 
    close(clientfd); 
} 

客戶端代碼

#include<sys/types.h> 
#include<sys/socket.h> 
#include<netinet/in.h> 
#include<fcntl.h> 
#include<string.h> 
#include<stdio.h> 

#define DESTPORT 3500 

int main() 
{ 

    struct sockaddr_in dest_addr; 

    int sockfd = socket(AF_INET,SOCK_STREAM,0); 

    dest_addr.sin_family = AF_INET; 
    dest_addr.sin_port = htons(DESTPORT); 
    dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    dest_addr.sin_zero[8]='\0'; 

    connect(sockfd,(struct sockaddr*)&dest_addr, sizeof(struct sockaddr)); 

    char msg[100]; 
    printf("Enter you message: "); 
    gets(&msg); 

    int w = write(sockfd, msg, strlen(msg)); 

    close(sockfd); 
    printf("Client Dying.....\n"); 

    return 0; 
} 

回答

1

服務器應該bind0.0.0.0(任何),除非你試圖限制訪問(在這種情況下,你應該真的使用防火牆,而不是端口綁定)。正確的方法實際上是:

struct addrinfo *ai, hints = { .ai_flags = AI_PASSIVE }; 
if (getaddrinfo(0, "1234", &hints, &ai)) goto error; 
int fd = socket(ai->ai_family, SOCK_STREAM, 0); 
bind(fd, ai->ai_addr, ai->ai_addrlen); 

當然,添加一些錯誤檢查。將「1234」替換爲您的端口號。

+0

解決我的情況只是我想要的方式..謝謝噸:-) 你可以建議一些很好的資源來了解有關現代套接字編程? – sachin11 2011-04-26 14:52:15

+0

對於'getaddrinfo','getnameinfo','socket','bind','''''''''''''''''''''''基本上是man頁面(或POSIX文檔,這裏是:http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html) connect','listen','accept','sendto','recvfrom'和'select'就是您所需要的全部。您在較舊的示例和教程中看到的所有複雜性只是傳統的包袱,並且不利於IPv6的支持和可移植性。 – 2011-04-26 14:55:58

+0

你爲什麼不在任何地方指定端口? – JeremyP 2011-04-26 15:08:45

0

127.0.0.1 localhost的是環回地址的機器你是目前。 如果您使用兩個單獨的框,您可能想要將其更改爲客戶端中的真實IP。

是的,客戶端通常但不總是在服務器的另一個物理盒上。 如果您需要,您可以在omne方塊上運行這兩件作品

+0

謝謝先生..所以,我將客戶端代碼中的IP地址更改爲服務器機器的IP地址..很好..但是,我應該如何處理服務器代碼上的IP地址,這裏是 my_addr .sin_addr.s_addr = inet_addr(「127.0.0.1」); – sachin11 2011-04-26 14:44:39

+1

你不應該手動捅[sin_addr.s_addr]等。這是90年代初期的一種不好的套接字編程,會給您帶來很多麻煩,並且很難支持IPv6。看到我的答案爲現代的方式來綁定套接字進行聆聽。 – 2011-04-26 14:47:56

+1

@ R. +1請參閱:http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html – 2011-04-28 16:29:41

1

1)正確。

2)在服務器端,您可以綁定到0.0.0.0,這意味着「所有(IPv4)接口」。

3)是的,你是對的。

4)最常見的是通過以太網交換機(或交叉以太網電纜,但很難找到)。

+0

非常感謝你:-) – sachin11 2011-04-26 14:49:53

0

1)說一臺電腦是服務器,另一臺是客戶端。現在,如果服務器代碼駐留在服務器計算機上並且客戶端上的客戶端代碼是?

我不認爲我從正確的角度理解這一點...... lol.If您的客戶端代碼在服務器端,您如何分配任何內存或調用客戶端計算機上的東西?

2)在我們爲bind()提供ip地址的服務器代碼中,它應該是我們可以通過ipconfig找到的系統的ip地址,或者它應該仍然是回送地址?

我們所擁有的手冊頁:

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 

「bind()的addr所分配指定的地址文件描述符的sockfd簡稱插座addrlen中指定的大小,以字節爲單位。傳統上,這個操作被稱爲「爲套接字分配一個名字」 在SOCK_STREAM套接字可能接收連接之前,通常需要使用bind()來分配一個本地地址(見accept(2 ))「。

就你而言,我想,你正在尋找127.0.0.1。簡而言之,你談到的地址更可能是你設置爲server_addr結構的地址。

3)在客戶端代碼中,我猜目的地的IP地址應該是服務器計算機的IP地址嗎?

是的。

4)最後也是最重要的是,如何連接兩臺計算機?

聽起來像一個經典的聊天室應用程序。 據我所知(我是新手......),UDP(用戶數據報協議)編程& API很值得一試。如果你想堅持TCP/IP,兩臺任意的計算機本質上不能連接到彼此,但都與服務器保持聯繫,服務器將成爲他們之間的基石。

更重要的是,我看着一些插座手冊頁:

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 

「的connect()系統調用連接用的sockfd到addr所指定的地址的文件描述符提到的插座的addrlen中參數指定addr的大小,addr中的地址格式取決於套接字sockfd的地址空間;有關更多詳細信息,請參閱套接字(2)。

我認爲這是以理論的方式完美地解釋你的問題。