1. Linux網絡編程與普通程序區別
網絡程序和普通的程序有一個最大的區別是網絡程序是由兩個部分組成的--客戶端和服務器端.
1.1 客戶端
主動與與外面的程序通信的程序。
例如使用ftp工具在Linux與Windows傳文件時,ftp程序就是一個客戶端程序,會去主動通信來獲取文件。
1.2 服務器
被動的等待外面的程序來與自己通信的程序。
例如在ftp工具使用過程中,與ftp進行通信的程序就是服務器,可以從服務器獲取文件。
2. Linux常用網絡調試命令
netstat
令netstat是用來顯示網絡的連接,路由表和接口統計等網絡的信息.netstat有許多的選項.
我們常用的選項是-na 用來顯示詳細的網絡狀態。
telnet
telnet是一個用來登錄遠程的程序,但是我們完全可以用這個程序來調試我們的服務端程序的.
比如我們的服務器程序在監聽8888端口,我們可以用
telnet localhost 8888
來查看服務端的狀況.
ping
ping 程序用來判斷網絡的狀態是否正常,最經常的一個用法是
ping 192.168.1.1
表示我們想查看到192.168.1.1的硬件連接是否正常
3. TCP/UDP協議簡單介紹
3.1 TCP協議
TCP(Transfer Control Protocol)傳輸控制協議是一種面向連接的協議, 在收發數據之前必須和對方建立可靠的連接(三次握手)。
當我們的網絡程序使用這個協議的時候, 網絡可以保證我們的客戶端和服務端的連接是可靠的,安全的.
當客戶端收到服務器的數據時,服務器會向客戶端發送一個信號表示收到了數據,否則數據就會重新發送。
一般傳輸文件,命令等數據使用TCP來傳輸,保證數據的可靠性。
3.2 UDP協議
UDP(User Datagram Protocol)用戶數據報協議是一種非面向連接的協議,它不與對方建立連接,而是直接就把數據包發送過去!
這種協議並不能保證我們的網絡程序的連接是可靠的。
一般視頻傳輸時使用UDP來進行傳輸,保證數據的實時性。
4. Linux下Socket編程
參考文章: [Linux網絡編程入門](http://blog.csdn.net/jenshy/archive/2006/04/18/667944.aspx)
4.1 TCP傳輸
服務器端: 客戶端(主動發起連接):
/* 相當於讀寫文件時的open函數,會返回一個sd描述符*/
a. sd = socket(); ---------------------------------------------- a. sd = socket();
/* 服務器一直在被動的響應請求,同時也在一直監測某個端口。
* bind函數可以將自己的ip,端口與sd綁定,
* 以後會監測ip與端口查看是否有數據傳輸過來
*/
b. bind(自己的ip,端口);
/* 啓動監測數據 */
c. listen();
/* 客戶端會發起連接,接受連接 */ /* 發送連接 */
d. accept(); ----------------------------------------------- b.connect(目的);
/* 發送數據 */
e. send(); ----------------------------------------------- c.recv();
/* 接受數據 */
f. recv(); ----------------------------------------------- d.send();
代碼示例(服務器端接受多個客戶端發送的數據,每個客戶端進行連接時都會服務器端都會創建一個子進程來打印出數據)
TCP通信服務器端程序 server.c :`
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* tcp協議服務器程序 */
int main(int argc, char **argv)
{
int ret;
int client_num = -1;
int server_sd;
int client_sd;
struct sockaddr_in SocketServerAddr;
struct sockaddr_in SocketClientAddr;
socklen_t adder_len;
int recv_len;
char buf[1000];
/* 1. socket
* AF_INET ---> ipv4協議
* SOCK_STREAM--> tcp協議
*/
server_sd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sd < 0)
{
printf("socket error\n\r");
}
/* 2.bind
* sd----------------->socket_id
* SocketServerAddr--->addr_and_port
*/
SocketServerAddr.sin_family = AF_INET; /* 與ipv4對應 */
SocketServerAddr.sin_port = htons(8888); /* 監聽端口,host to short */
SocketServerAddr.sin_addr.s_addr = INADDR_ANY; /* 監聽地址爲本機的所有ip */
memset(SocketServerAddr.sin_zero, 0, 8);
ret = bind(server_sd, (struct sockaddr *)&SocketServerAddr,sizeof (struct sockaddr));
if (ret == -1)
{
printf("bind error\n\r");
return -1;
}
/* 3.listen
* backlog:設置請求排隊的最大長度.當有多個客戶端程序和服務端相連時,
* 使用這個表示可以介紹的排隊長度.
*/
ret = listen(server_sd, 10);
if (-1 == ret )
{
printf("listen error\n\r");
return -1;
}
/* 4.accept */
while (1)
{
adder_len = sizeof (struct sockaddr);
client_sd = accept(server_sd, (struct sockaddr *)&SocketClientAddr,&adder_len );
if (client_sd == -1)
{
printf("accept error\n\r");
return -1;
}
else
{
client_num++;
/* network to ascii */
printf("sucess connect client %s\n", inet_ntoa(SocketClientAddr.sin_addr));
}
/* 每當主進程接受到一個客戶端連接時創建一個子進程,
子進程接收客戶端數據並打印 */
if (!fork())
{
while (1)
{
/* 子進程一直讀取數據 */
recv_len = recv(client_sd, buf, 1000, 0);
if (recv_len <= 0)
{
close(client_sd);
return -1;
}
buf[recv_len] = '\0';
printf("recv client %d : %s\n\r", client_num, buf);
}
}
}
close(server_sd);
return 0;
}
TCP通信客戶端程序client.c:
/* client.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int ret;
int client_sd;
int send_len;
char send_buf[1000];
char *tmp;
struct sockaddr_in SocketClientAddr;
if (argc != 2)
{
printf("Usage: \n");
printf("%s <server_ip>", argv[0]);
return -1;
}
/* 1. socket
* AF_INET ---> ipv4協議
* SOCK_STREAM--> tcp協議
*/
client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (client_sd < 0)
{
printf("socket error\n\r");
return -1;
}
SocketClientAddr.sin_family = AF_INET; /* 與ipv4對應 */
SocketClientAddr.sin_port = htons(8888); /* 監聽端口,host to short */
inet_aton(argv[1],&SocketClientAddr.sin_addr); /* 監聽地址爲本機的所有ip */
memset(SocketClientAddr.sin_zero, 0, 8);
ret = connect(client_sd, (struct sockaddr *)&SocketClientAddr,sizeof(struct sockaddr));
if (-1 == ret )
{
printf("connect error\n\r");
return -1;
}
while (1)
{
if (fgets(send_buf, 1000, stdin))
{
send_len = send(client_sd, send_buf, strlen(send_buf), 0);
if (send_len <= 0)
{
printf("send error\n\r");
close(client_sd);
return -1;
}
}
}
close(client_sd);
return 0;
}
4.2 UDP傳輸
服務器端: 客戶端(主動發起連接):
/* 相當於讀寫文件時的open函數,會返回一個sd描述符*/
a. sd = socket(); -------------------------------------------------- a. sd = socket();
/* 不會真正去連接,只是爲了包含目的信息 */
/* 可以不用連接,但是在發生數據時要使用sento函數發送,參數包含目的地址等信息 */
/* 服務器一直在被動的響應請求,同時也在一直監測某個端口。 b. connect()
* bind函數可以將自己的ip,端口與sd綁定,
* 以後會監測ip與端口查看是否有數據傳輸過來
*/
b. bind(自己的ip,端口);
/* 無需listen,accept */
/* 發送數據 */
e. sendto(); ----------------------------------------------- c.recvfrom();
/* 接受數據 */
f. recvfrom(); ----------------------------------------------- d.sendto();
UDP通信服務器程序 : /* server.c */
/* server.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int ret;
int addr_len;
int recv_len;
int server_sd;
struct sockaddr_in SocketServerAddr;
struct sockaddr_in SocketClientAddr;
char buf[1000];
server_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_sd < 0)
{
printf("socket error\n");
return -1;
}
SocketServerAddr.sin_family = AF_INET;
SocketServerAddr.sin_port = htons(8888);
SocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(SocketServerAddr.sin_zero, 0, 8);
ret = bind(server_sd, (struct sockaddr *)&SocketServerAddr,sizeof (struct sockaddr));
if (-1 == ret)
{
printf("bind error\n");
return -1;
}
while (1)
{
addr_len = sizeof (struct sockaddr);
recv_len = recvfrom(server_sd, buf, 999, 0, (struct sockaddr *)&SocketClientAddr, &addr_len);
if (recv_len > 0)
{
buf[recv_len] = '\0';
printf("Get msg from %s : %s\n", inet_ntoa(SocketClientAddr.sin_addr), buf);
}
else
{
close(server_sd);
return -1;
}
}
return 0;
}
UDP通信客戶端程序:`/* client.c */
/* client.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
//#define CONNECT
int main(int argc, char **argv)
{
int ret;
int client_sd;
int send_len;
int addr_len;
struct sockaddr_in SocketClientAddr;
char buf[1000];
if (argc != 2)
{
printf("Usage: \n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
client_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (client_sd < 0)
{
printf("socket error\n");
return -1;
}
SocketClientAddr.sin_family = AF_INET;
SocketClientAddr.sin_port = htons(8888);
if (inet_aton(argv[1], &SocketClientAddr.sin_addr) == 0)
{
printf("invalid address\n");
return -1;
}
memset(SocketClientAddr.sin_zero, 0, 8);
#ifdef CONNECT
ret = connect(client_sd, (struct sockaddr *)&SocketClientAddr, sizeof (struct sockaddr));
if (-1 == ret)
{
printf("connect error\n");
return -1;
}
#endif
while (1)
{
if (fgets(buf, 1000, stdin))
{
#ifdef CONNECT
send_len = send(client_sd, buf, strlen(buf), 0);
if (send_len <= 0)
{
printf("send error\n");
return -1;
}
#else
send_len = sendto(client_sd, buf, strlen(buf), 0, (const struct sockaddr *)&SocketClientAddr, sizeof (struct sockaddr));
if (send_len <= 0)
{
printf("send error\n");
return -1;
}
#endif
}
}
return 0;
}