Ⅰ linux手冊翻譯——socket(2)
socket - 創建一個用於通信的端點
socket() 創建用於通信的端點並返回引用該端點的文件描述符。 成功調用時返回的文件描述符,將是當前沒有被進程打開的所有文件描述符中編號最低的。
domain 參數指定一個通信域; 以決定用於通信的協議族。 這些系列在 <sys/socket.h> 中定義。 目前 Linux 內核理解的格式包括:
當然最常用的當然是 AF_INET ,即IPV4。
上述地址族的更多詳細信息以及其他幾個地址族的信息可以在 address_families(7) 中找到。
套接字具有指定的 type ,它指定了通信語義。 當前定義的類型有:
某些套接字類型可能不會被所有協議族實現。
從 Linux 2.6.27 開始,type 參數有第二個用途:除了指定套接字類型之外,它還可以包含以下任何值的按位或,以修改 socket() 的行為:
老朋友了,上述兩個,第一個是非阻塞,第二個是執行exec時自動關閉。
protocol 指定要與套接字一起使用的特定協議。 通常只存在一個協議來支持給定協議族中的特定套接字類型 ,在這種情況下,protocol 可以指定為 0。但是,可能存在許多協議,在這種情況下,必須在此指定特定協議方式。 特定協議對應的編號可以查看文件: /etc/protocols
SOCK_STREAM 類型的套接字是全雙工位元組流。 它們不保留記錄邊界。 流套接字必須處於連接狀態,然後才能在其上發送或接收任何數據。 到另一個套接字的連接是通過 connect(2) 調用創建的。 連接後,可以使用 read(2) 和 write(2) 調用或 其變體send(2) 和 recv(2) 的來傳輸數據。 當會話完成時,可以執行 close(2)。 帶外數據也可以按照 send(2) 中的描述進行傳輸,並按照 recv(2) 中的描述進行接收。
實現 SOCK_STREAM 的通信協議確保數據不會丟失或重復。 如果協議的緩沖空間中存在一條數據在合理的時間內不能成功傳輸,則認為該連接已失效。 當 SO_KEEPALIVE 在套接字上啟用時,將會以特定於協議的方式檢查另一端是否仍然存在。 如果進程在損壞的流上發送或接收,則會引發 SIGPIPE 信號; 這會導致不處理信號的進程退出。 SOCK_SEQPACKET 套接字使用與 SOCK_STREAM 套接字相同的系統調用。 唯一的區別是 read(2) 調用將只返回請求的數據量,到達數據包中剩餘的其他數據都將被丟棄。 傳入數據報中的所有消息邊界也被保留。
SOCK_DGRAM 和 SOCK_RAW 套接字允許將數據報發送到在 sendto(2) 調用中指定的通信者。 數據報通常用 recvfrom(2) 接收,它返回下一個數據報及其發送者的地址。
SOCK_PACKET 是一種過時的套接字類型,用於直接從設備驅動程序接收原始數據包。 改用 packet(7)。
An fcntl(2) F_SETOWN operation can be used to specify a process or process group to receive a SIGURG signal when the out-of-band data arrives or SIGPIPE signal when a SOCK_STREAM connection breaks unexpectedly. This operation may also be used to set the process or process group that receives the I/O and asynchronous notification of I/O events via SIGIO. Using F_SETOWN is equivalent to an ioctl(2) call with the FIOSETOWN or SIOCSPGRP argument.
When the network signals an error condition to the protocol mole (e.g., using an ICMP message for IP) the pending error flag is set for the socket. The next operation on this socket will return the error code of the pending error. For some protocols it is possible to enable a per-socket error queue to retrieve detailed information about the error; see IP_RECVERR in ip(7).
套接字的操作由套接字選項控制。 這些選項在 <sys/socket.h> 中定義。 函數setsockopt(2) 和getsockopt(2) 用於設置和獲取選項。對於選項的描述,詳見socket(7).
成功時,將返回新套接字的文件描述符。 出錯時,返回 -1,並設置 errno 以指示錯誤。
POSIX.1-2001, POSIX.1-2008, 4.4BSD.
The SOCK_NONBLOCK and SOCK_CLOEXEC flags are Linux-specific.
socket() appeared in 4.2BSD. It is generally portable to/from non-BSD systems supporting clones of the BSD socket layer (including System V variants).
在 4.x BSD 下用於協議族的清單常量是 PF_UNIX、PF_INET 等,而 AF_UNIX、AF_INET 等用於地址族。 但是,BSD 手冊頁已經承諾:「協議族通常與地址族相同」,隨後的標准到處都使用 AF_*。
Ⅱ linux下的socket編程在哪進行
LINUX下的SOCKET編程?應該所有語言都有相應的SOCKET編程介面。
C/C++、JAVA,python,RUBY,PERL,甚至是回SCEME。
只不過,其他幾種都是跨平答台的,不算是單獨的LINUX下SOCKET編程。一般C語言和C++才這么說。因為LINUX下的介面和WINDOWS不一樣。
想知道介面有哪些的話,你得查手冊或是看《UNIX環境高級編程》這類書,書上會有LINUX/UNIX的C編程介面。
編譯環境的話,只要是C語言編譯器,LINUX支持的主要是GCC,LINUX下的開發環境IDE也默認都用GCC了,比如CODEBLOCKS、GEANY什麼的。按下編譯、運行按鈕就行了,和WINDOWS下開發的步驟差不多,只是介面不一樣。
如果要用命令行的話,也不難,代碼寫好了,gcc 一下就可以編譯了。不過,看你的水平,算了吧……要麼安心學一下LINUX下編程,要麼老實地用IDE。
問這種問題,讓人很難回答的……在哪進行,當然在LINUX下,在LINUX的C語言代碼文件里,什麼編譯環境?C語言的編譯環境……什麼編譯工具,C語言的編譯工具,比如GCC。
Ⅲ linux socket是什麼意思
socket介面是TCP/IP網路的API,socket介面定義了許多函數或常式,程序員可以用它們來開發TCP/IP網路上的應用程序。要學Internet上的TCP/IP網路編程,必須理解socket介面。
socket介面設計者最先是將介面放在Unix操作系統裡面的。如果了解Unix系統的輸入和輸出的話,就很容易了解socket了。網路的 socket數據傳輸是一種特殊的I/O,socket也是一種文件描述符。socket也具有一個類似於打開文件的函數調用socket(),該函數返回一個整型的socket描述符,隨後的連接建立、數據傳輸等操作都是通過該socket實現的。常用的socket類型有兩種:流式socket (SOCK_STREAM)和數據報式socket(SOCK_DGRAM)。流式是一種面向連接的socket,針對於面向連接的TCP服務應用;數據報式socket是一種無連接的socket,對應於無連接的UDP服務應用。
socket建立
為了建立socket,程序可以調用socket函數,該函數返回一個類似於文件描述符的句柄。socket函數原型為:
int socket(int domain, int type, int protocol); domain指明所使用的協議族,通常為PF_INET,表示互聯網協議族(TCP/IP協議族);type參數指定socket的類型: SOCK_STREAM 或SOCK_DGRAM,socket介面還定義了原始socket(SOCK_RAW),允許程序使用低層協議;protocol通常賦值 "0"。 socket()調用返回一個整型socket描述符,你可以在後面的調用使用它。
socket描述符是一個指向內部數據結構的指針,它指向描述符表入口。調用socket函數時,socket執行體將建立一個socket,實際上 "建立一個socket"意味著為一個socket數據結構分配存儲空間。socket執行體為你管理描述符表。 兩個網路程序之間的一個網路連接包括五種信息:通信協議、本地協議地址、本地主機埠、遠端主機地址和遠端協議埠。socket數據結構中包含這五種信息。
socket配置
通過socket調用返回一個socket描述符後,在使用socket進行網路傳輸以前,必須配置該socket。面向連接的socket客戶端通過調用connect函數在socket數據結構中保存本地和遠端信息。無連接socket的客戶端和服務端以及面向連接socket的服務端通過調用 bind函數來配置本地信息。
bind函數將socket與本機上的一個埠相關聯,隨後你就可以在該埠監聽服務請求。bind函數原型為:
int bind(int sockfd,struct sockaddr*my_addr, int addrlen); Sockfd是調用socket函數返回的socket描述符,my_addr是一個指向包含有本機IP地址及埠號等信息的sockaddr類型的指針;addrlen常被設置為sizeof(struct sockaddr)。
struct sockaddr結構類型是用來保存socket信息的:
struct sockaddr {
unsigned short sa_family; /*地址族,AF_xxx*/ char sa_data[14]; /*14位元組的協議地址*/ };
sa_family一般為AF_INET,代表Internet(TCP/IP)地址族;sa_data則包含該socket的IP地址和埠號。 另外還有一種結構類型: struct sockaddr_in {
short int sin_family; /*地址族*/
unsigned short int sin_port; /*埠號*/ struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8];/*填0保持與sockaddr同樣大小*/ };
這個結構更方便使用。sin_zero用來將sockaddr_in結構填充到與struct sockaddr同樣的長度,可以用bzero()或memset()函數將其置為零。指向
sockaddr_in 的指針和指向sockaddr的指針可以相互轉換,這意味著如果一個函數所需參數類型是sockaddr時,你可以在函數調用的時候將一個指向 sockaddr_in的指針轉換為指向sockaddr的指針;或者相反。 使用bind函數時,可以用下面的賦值實現自動獲得本機IP地址和隨機獲取一個沒有被佔用的埠號:
my_addr.sin_port=0; /* 系統隨機選擇一個未被使用的埠號*/ my_addr.sin_addr.s_addr=INADDR_ANY; /* 填入本機IP地址*/
通過將my_addr.sin_port置為0,函數會自動為你選擇一個未佔用的埠來使用。同樣,通過將my_addr.sin_addr.s_addr置為INADDR_ANY,系統會自動填入本機IP地址。
注意在使用bind函數是需要將sin_port和sin_addr轉換成為網路位元組優先順序;而sin_addr則不需要轉換。
計算機數據存儲有兩種位元組優先順序:高位位元組優先和低位位元組優先。Internet上數據以高位位元組優先順序在網路上傳輸,所以對於在內部是以低位位元組優先方式存儲數據的機器,在Internet上傳輸數據時就需要進行轉換,否則就會出現數據不一致。
htonl():把32位值從主機位元組序轉換成網路位元組序 htons():把16位值從主機位元組序轉換成網路位元組序 ntohl():把32位值從網路位元組序轉換成主機位元組序 ntohs():把16位值從網路位元組序轉換成主機位元組序
bind()函數在成功被調用時返回0;出現錯誤時返回 "-1"並將errno置為相應的錯誤號。需要注意的是,在調用bind函數時一般不要將埠號置為小於1024的值,因為1到1024是保留埠號,你可以選擇大於1024中的任何一個沒有被佔用的埠號。
連接建立
面向連接的客戶程序使用connect函數來配置socket並與遠端伺服器建立一個TCP連接,其函數原型為:
int connect(int sockfd, struct sockaddr*serv_addr,int addrlen); Sockfd 是socket函數返回的socket描述符;serv_addr是包含遠端主機IP地址和埠號的指針;addrlen是遠端地質結構的長度。 connect函數在出現錯誤時返回-1,並且設置errno為相應的錯誤碼。
進行客戶端程序設計無須調用bind(),因為這種情況下只需知道目的機器的IP地址,而客戶通過哪個埠與伺服器建立連接並不需要關心,socket執行體為你的程序自動選擇一個未被佔用的埠,並通知你的程序數據什麼時候到達埠。
connect函數啟動和遠端主機的直接連接。只有面向連接的客戶程序使用socket時才需要將此socket與遠端主機相連。無連接協議從不建立直接連接。面向連接的伺服器也從不啟動一個連接,它只是被動的在協議埠監聽客戶的請求。
listen函數使socket處於被動的監聽模式,並為該socket建立一個輸入數據隊列,將到達的服務請求保存在此隊列中,直到程序處理它們。 int listen(int sockfd, int backlog);
Sockfd 是socket系統調用返回的socket 描述符;backlog指定在請求隊列中允許的最大請求數,進入的連接請求將在隊列中等待accept()它們(參考下文)。Backlog對隊列中等待服務的請求的數目進行了限制,大多數系統預設值為20。如果一個服務請求到來時,輸入隊列已滿,該socket將拒絕連接請求,客戶將收到一個出錯信息。
當出現錯誤時listen函數返回-1,並置相應的errno錯誤碼。
accept()函數讓伺服器接收客戶的連接請求。在建立好輸入隊列後,伺服器就調用accept函數,然後睡眠並等待客戶的連接請求。 int accept(int sockfd, void*addr, int*addrlen);
sockfd是被監聽的socket描述符,addr通常是一個指向sockaddr_in變數的指針,該變數用來存放提出連接請求服務的主機的信息(某台主機從某個埠發出該請求);addrten通常為一個指向值為sizeof(struct sockaddr_in)的整型指針變數。出現錯誤時accept函數返回-1並置相應的errno值。 首先,當accept函數監視的 socket收到連接請求時,socket執行體將建立一個新的socket,執行體將這個新socket和請求連接進程的地址聯系起來,收到服務請求的初始socket仍可以繼續在以前的 socket上監聽,同時可以在新的socket描述符上進行數據傳輸操作。 數據傳輸
send()和recv()這兩個函數用於面向連接的socket上進行數據傳輸。 int send(int sockfd, const void*msg, int len, int flags);
Sockfd是你想用來傳輸數據的socket描述符;msg是一個指向要發送數據的指針;Len是以位元組為單位的數據的長度;flags一般情況下置為0(關於該參數的用法可參照man手冊)。
send()函數返回實際上發送出的位元組數,可能會少於你希望發送的數據。在程序中應該將send()的返回值與欲發送的位元組數進行比較。當send()返回值與len不匹配時,應該對這種情況進行處理。
int recv(int sockfd,void*buf,int len,unsigned int flags);
Ⅳ linux手冊翻譯——send(2)
send, sendto, sendmsg - send a message on a socket
系統調用 send()、sendto() 和 sendmsg() 用於將消息傳輸到另一個套接字。
僅當套接字處於連接狀態時才可以使用 send() 調用(以便知道預期的接收者, 也就是說send()僅僅用於數據流類型的數據發送 ,對於TCP,服務端和客戶端都可以使用send/recv;但是對於UDP,只能是客戶端使用send/recv,服務端只能使用sendto/recvfrom,因為客戶端是進行了connect操作知道要發送和接受的地址)。send() 和 write(2) 之間的唯一滲衡區別是存在 flags 參數。此外,
send(sockfd, buf, len, flags);
等價於
sendto(sockfd, buf, len, flags, NULL, 0);
參數 sockfd 是發送者套接字的文件描述符。
如果在連接模式的套接字(即套接字類型為SOCK_STREAM、SOCK_SEQPACKET)上使用 sendto(),則參數 dest_addr 和 addrlen 將被忽略(當它們不是NULL和0時可能返回錯誤EISCONN),若套接字沒有實際連接(還沒有三次握手建立連接)將返回錯誤ENOTCONN。 否則,目標地址由 dest_addr 給出, addrlen 指定其大小。 對於 sendmsg(),目標地址由 msg.msg_name 給出, msg.msg_namelen 指定其大小。
對於 send() 和 sendto(),消息位於 buf 中,長度為 len 。 對於sendmsg(),消息存放於 msg.msg_iov 元素指向 數組數據區 (見下)中。 sendmsg() 調用還允許發送輔助數據(也稱為控制信息) 。
如果消息太長而無法通過底層協議原子傳遞( too long to pass atomically through the underlying protocol ),則返回錯誤 EMSGSIZE,並且不會傳輸消息。
No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.
當消息轎陵不適合套接字的發送緩沖區時,send() 通常會阻塞,除非套接字已置於非阻塞 I/O 模式。 在這種情況下,在非阻塞模式下它會失敗並顯示錯誤 EAGAIN 或 EWOULDBLOCK。 select(2) 調用可用於確定何時可以發送更多數據 。
上面的的描述還是很籠統的,以TCP為例,按我的理解,我認為只要發送緩沖區有空閑位置,且此時協議棧沒有向網路發送數據,那麼就可以寫入,對於阻塞模式,直到所有數據寫入到緩沖區,就會返回,否則一直阻塞,對於非阻塞模式,是有一個超時時間的,這個由 SO_SNDTIMEO 選項控制,詳細見 socket(7) ,如果當前有空閑位置可以發即當前可寫入,那麼就寫入到緩沖區,知道超時之前寫入多少算多少,然後返回成功寫入的位元組數,如果超時時任何數據都沒寫出去,或者當前就是閉喊戚不可寫入,那麼返回-1 ,並設置errno為 EAGAIN 或 EWOULDBLOCK。
The flags argument is the bitwise OR of zero or more of the following flags.
sendmsg() 使用的 msghdr 結構的定義如下:
對於未連接的套接字 msg_name 指定數據報的目標地址,它指向一個包含地址的緩沖區; msg_namelen 欄位應設置為地址的大小。 對於連接的套接字,這些欄位應分別指定為 NULL 和 0。 這里的未連接指的是數據報協議,連接指的是數據流協議
The msg_iov and msg_iovlen fields specify scatter-gather locations, as for writev(2).
msg_iov是一個buffer數組:
使用 msg_control 和 msg_controllen 成員發送控制信息(輔助數據)。 內核可以處理的每個套接字最大控制緩沖區長度由 /proc/sys/net/core/optmem_max 中的值限制; 見 socket(7) 。 有關在各種套接字域中使用輔助數據的更多信息,請參閱 unix(7) 和 ip(7)。
msg_flags 欄位被忽略。
成功時,返回成功發送的位元組數,這個位元組數並不一定和我們的緩沖區大小相同 。 出錯時,返回 -1,並設置 errno 以指示錯誤。
這些是套接字層生成的一些標准錯誤。 底層協議模塊可能會產生和返回額外的錯誤; 請參閱它們各自的手冊頁。
4.4BSD, SVr4, POSIX.1-2001. These interfaces first appeared in 4.2BSD.
POSIX.1-2001 describes only the MSG_OOB and MSG_EOR flags. POSIX.1-2008 adds a specification of MSG_NOSIGNAL. The MSG_CONFIRM flag is a Linux extension.
根據 POSIX.1-2001,msghdr 結構的 msg_controllen 欄位應該是 socklen_t 類型,而 msg_iovlen 欄位應該是 int 類型,但是 glibc 目前將兩者都視為 size_t。
有關可用於在單個調用中傳輸多個數據報的 Linux 特定系統調用的信息,請參閱 sendmmsg(2)。
Linux may return EPIPE instead of ENOTCONN.
getaddrinfo(3) 中顯示了使用 send() 的示例。
Ⅳ linux手冊翻譯——recv(2)
recv, recvfrom, recvmsg - receive a message from a socket
recv()、recvfrom() 和 recvmsg() 調用用於從套接字接收消息。 它們可用於在UDP和TCP的套接字上接收數據。 本頁首先介紹了所有三個系統調用的共同特點,然後介紹了調用之間的區別。
recv() 和 read(2) 之間的唯一區別是 flags 的存在。 使用腔弊棗零標志參數,recv() 通常等效於 read(2) (但請參閱 NOTES),且
recv(sockfd, buf, len, flags);
等價於
recvfrom(sockfd, buf, len, flags, NULL, NULL);
所有三個調用都在成功完成時返回消息的長度。 如果消息太長而無法放入提供的緩沖區,則 可能 會丟棄多餘的位元組,具體 取決於接收消息的套接字類型 ,顯然TCP是不可能丟棄的。
如果套接字上卜滾沒有可用消息,則接收調用將等待消息到達,除非套接字是非阻塞伍拆的(請參閱 fcntl(2)),在這種情況下,將返回值 -1 並將 errno 設置為 EAGAIN 或 EWOULDBLOCK。 recv_()調用通常會返回任何可用的數據,只要拿到數據就會立馬返回,最多返回指定緩沖區大小的數據,但是並不會等待到讓緩沖區滿 ,除非設置了 MSG_WAITALL 標志,見下。
應用程序可以使用 select(2)、poll(2) 或 epoll(7) 來確定更多數據何時到達。
The flags argument is formed by ORing one or more of the following values:
ee_errno contains the errno number of the queued error. ee_origin is the origin code of where the error originated. The other fields are protocol-specific. The macro SOCK_EE_OFFENDER returns a pointer to the address of the network object where the error originated from given a pointer to the ancillary message. If this address is not known, the sa_family member of the sockaddr contains AF_UNSPEC and the other fields of the sockaddr are undefined. The payload of the packet that caused the error is passed as normal data.
For local errors, no address is passed (this can be checked with the cmsg_len member of the cmsghdr ). For error receives, the MSG_ERRQUEUE flag is set in the msghdr . After an error has been passed, the pending socket error is regenerated based on the next queued error and will be passed on the next socket operation.
recvfrom() 將接收到的消息放入緩沖區 buf 。 調用者必須在 len 中指定緩沖區的大小。
如果調用者希望拿到消息的原地址, 並且底層協議可以提供消息的源地址時,應將 src_addr 設置為指向用於接收消息原地址的緩沖區。 在這種情況下, addrlen 是一個 value-result 參數。 在調用之前,它應該被初始化為與 src_addr 關聯的緩沖區的大小。 返回時,addrlen 被更新以包含源地址的實際大小。 如果提供的緩沖區太小,則截斷返回的地址; 在這種情況下, addrlen 將返回一個大於提供給調用的值。
如果調用者對源地址不感興趣,則應將 src_addr 和 addrlen 指定為 NULL。
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
recv() 調用通常僅用於已連接的套接字(請參閱 connect(2))。 相當於調用:
recvfrom(fd, buf, len, flags, NULL, 0);
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
recvmsg() 調用使用 msghdr 結構來 最小化直接提供的參數數量 。 這個結構在 <sys/socket.h> 中定義如下:
msg_name 欄位指向調用者分配的緩沖區,如果套接字未連接( 特指UDP的服務端 ),則該緩沖區用於返回源地址。 調用者應在此調用之前將 msg_namelen 設置為此緩沖區的大小; 從成功調用返回後,msg_namelen 將包含返回地址的長度。 如果應用程序不需要知道源地址,可以將 msg_name 指定為 NULL。
The fields msg_iov and msg_iovlen describe scatter-gather locations, as discussed in readv(2).
需要注意的是 msg_iov 和 msg_iovlen 描述了一個 struct iovec 類型的數組, msg_iovlen 表示數組的元素個數,而struct iovec則是描述了一個緩沖區
欄位 msg_control 指向用於其他協議控制相關消息或雜項輔助數據的緩沖區。 當recvmsg()被調用時, msg_controllen 為 msg_contro l中可用緩沖區的長度; 從成功調用返回時,它將被設置為控制消息序列的長度。
控制消息的格式為:
只能通過 cmsg(3) 中定義的宏訪問輔助數據。
例如,Linux 使用這種輔助數據機制通過 UNIX 域套接字傳遞擴展錯誤、IP 選項或文件描述符。 有關在各種套接字域中使用輔助數據的更多信息,請參閱 unix(7) 和 ip(7)。
msghdr 中的 msg_flags 欄位在 recvmsg() 返回時設置 。 它可以包含幾個標志:
這些調用返回接收到的位元組數,如果發生錯誤,則返回 -1。 如果發生錯誤,則設置 errno 以指示錯誤。
當流套接字對等端執行有序關閉(orderly shutdown)時,返回值將為 0(傳統的「文件結束」返回)。
各種域(例如 UNIX 和 Internet 域)中的數據報套接字允許零長度數據報。 當收到這樣的數據報時,返回值為 0。
如果從流套接字接收的請求位元組數為 0,則也可能返回值 0。
這些是套接字層生成的一些標准錯誤。 底層協議模塊可能會產生和返回額外的錯誤; 查看他們的手冊頁。
POSIX.1-2001, POSIX.1-2008, 4.4BSD (these interfaces first appeared in 4.2BSD).
POSIX.1 describes only the MSG_OOB, MSG_PEEK, and MSG_WAITALL flags.
如果零長度數據報未決,則帶有零標志參數的 read(2) 和 recv() 提供不同的行為。 在這種情況下, read(2) 不起作用(數據報保持掛起),而 recv() 消耗掛起的數據報。
socklen_t 類型是由 POSIX 發明的。 另見 accept(2) 。
根據 POSIX.1,msghdr 結構的 msg_controllen 欄位類型為 socklen_t,而 msg_iovlen 欄位類型為 int,但 glibc 目前將兩者設置為 size_t。
有關可用於在單個調用中接收多個數據報的 Linux 特定系統調用的信息,請參閱 recvmmsg(2)。
getaddrinfo(3) 中顯示了使用 recv() 的示例。
Ⅵ linux C語言編程,socket實現的即使通訊系統
//服務端server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define SERVPORT 6000 /*伺服器監聽埠號 */
#define BACKLOG 10 /* 最大同時連接請求數 */
#define MAXDATASIZE 100
main()
{
char buf[MAXDATASIZE];
int sockfd,client_fd; /*sock_fd:監聽socket;client_fd:數據傳輸socket */
struct sockaddr_in my_addr; /* 本機地址信息 */
struct sockaddr_in remote_addr; /* 客戶端地址信息 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket創建出錯!");
exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind出錯!");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1)
{
perror("listen出錯!");
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
{
perror("accept出錯");
continue;
}
printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
if (!fork())
{ /* 子進程代碼段 */
if ((recvbytes=recv(client_fd, buf, MAXDATASIZE, 0)) ==-1)
{
perror("recv出錯!");
close(client_fd);
exit(0);
}
buf[recvbytes] = '\0';
printf("from client Received: %s",buf);
if (send(client_fd, "thanks!\n", 8, 0) == -1)
perror("send出錯!");
close(client_fd);
exit(0);
}
close(client_fd);
}
}
//客戶端client.c
#include<stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 6000
#define MAXDATASIZE 100
main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if (argc < 2)
{
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
if((host=gethostbyname(argv[1]))==NULL)
{
herror("gethostbyname出錯!");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket創建出錯!");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect出錯!");
exit(1);
}
if (send(sockfd, "hello!\n", 7, 0) == -1)
{
perror("send出錯!");
exit(1);
}
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1)
{
perror("recv出錯!");
exit(1);
}
buf[recvbytes] = '\0';
printf("Received: %s",buf);
close(sockfd);
}
Ⅶ Linux下Socket編程 怎樣實現客戶端之間互相通信
網路的Socket數據傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個類似於打開文件的函數調用Socket(),該函數返回一個整型的Socket描述符,隨後的連接建立、數據傳輸等操作都是通過該Socket實現的。
下面用Socket實現一個windows下的c語言socket通信例子,這里我們客戶端傳遞一個字元串,伺服器端進行接收。
【伺服器端】
#include"stdafx.h"
#include<stdio.h>
#include<winsock2.h>
#include<winsock2.h>
#defineSERVER_PORT5208//偵聽埠
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret,nLeft,length;
SOCKETsListen,sServer;//偵聽套接字,連接套接字
structsockaddr_insaServer,saClient;//地址信息
char*ptr;//用於遍歷信息的指針
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//創建Socket,使用TCP協議
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sListen==INVALID_SOCKET)
{
WSACleanup();
printf("socket()faild! ");
return;
}
//構建本地地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意轉化為網路位元組序
saServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//使用INADDR_ANY指示任意地址
//綁定
ret=bind(sListen,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("bind()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//關閉套接字
WSACleanup();
return;
}
//偵聽連接請求
ret=listen(sListen,5);
if(ret==SOCKET_ERROR)
{
printf("listen()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//關閉套接字
return;
}
printf("Waitingforclientconnecting! ");
printf("Tips:Ctrl+ctoquit! ");
//阻塞等待接受客戶端連接
while(1)//循環監聽客戶端,永遠不停止,所以,在本項目中,我們沒有心跳包。
{
length=sizeof(saClient);
sServer=accept(sListen,(structsockaddr*)&saClient,&length);
if(sServer==INVALID_SOCKET)
{
printf("accept()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//關閉套接字
WSACleanup();
return;
}
charreceiveMessage[5000];
nLeft=sizeof(receiveMessage);
ptr=(char*)&receiveMessage;
while(nLeft>0)
{
//接收數據
ret=recv(sServer,ptr,5000,0);
if(ret==SOCKET_ERROR)
{
printf("recv()failed! ");
return;
}
if(ret==0)//客戶端已經關閉連接
{
printf("Clienthasclosedtheconnection ");
break;
}
nLeft-=ret;
ptr+=ret;
}
printf("receivemessage:%s ",receiveMessage);//列印我們接收到的消息。
}
//closesocket(sListen);
//closesocket(sServer);
//WSACleanup();
}
【客戶端】
#include"stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
#defineSERVER_PORT5208//偵聽埠
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret;
SOCKETsClient;//連接套接字
structsockaddr_insaServer;//地址信息
char*ptr;
BOOLfSuccess=TRUE;
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//確認WinSockDLL支持版本2.2
if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf("InvalidWinSockversion! ");
return;
}
//創建Socket,使用TCP協議
sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sClient==INVALID_SOCKET)
{
WSACleanup();
printf("socket()failed! ");
return;
}
//構建伺服器地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意轉化為網路節序
saServer.sin_addr.S_un.S_addr=inet_addr("192.168.1.127");
//連接伺服器
ret=connect(sClient,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("connect()failed! ");
closesocket(sClient);//關閉套接字
WSACleanup();
return;
}
charsendMessage[]="hellothisisclientmessage!";
ret=send(sClient,(char*)&sendMessage,sizeof(sendMessage),0);
if(ret==SOCKET_ERROR)
{
printf("send()failed! ");
}
else
printf("clientinfohasbeensent!");
closesocket(sClient);//關閉套接字
WSACleanup();
}
Ⅷ 求linux下的socket 編程
看這個代碼你最好了解一下tcp協議,了解一下三次握手機制,要不然你可能看不懂,當初我們學到這的時候學了一天的tcp....還有,就是把下面代碼分開放到2個.c文件中,必須先運行伺服器端,再運行客戶端
//伺服器端的代碼
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/socket.h>
4 #include <unistd.h>
5 #include <netinet/in.h>
6 #include <sys/stat.h>
7 #include <stdlib.h>
8 #include <arpa/inet.h>
9
10 #define LOCAL_PORT 1234
11 #define MAX_LEN 512
12 #define MAX_NUM 5
13
14 int main(int argc, char *argv[])
15 {
16 int sock_fd, sock_data;
17 int ret, len_addr;
18 char buf[MAX_LEN];
19 ssize_t len;
20 struct sockaddr_in local_addr, remote_addr;
21
22 sock_fd = socket(AF_INET, SOCK_STREAM, 0); //創建套接字,sock_fd是套接字描述符,類似我們的身份證號碼
23 if (sock_fd < 0)
24 {
25 perror("socket()");
26 return sock_fd;
27 }
28
29 local_addr.sin_family = AF_INET;// 協議族,ipv4
30 local_addr.sin_port = htons(LOCAL_PORT);// 把伺服器埠轉換成網路位元組序
31 local_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//把字元串形式的ip轉換成網路位元組序
32
33 ret = bind(sock_fd, (struct sockaddr *)&local_addr, (size_t)sizeof(local_addr));// 把sock_fd和本機ip,埠邦定
34 if (ret < 0)
35 {
36 perror("bind()");
37 close(sock_fd);
38 return ret;
39 }
40
41 ret = listen(sock_fd, MAX_NUM);//監聽socket
42 if (ret)
43 {
44 perror("listen()");
45 close(sock_fd);
46 return ret;
47 }
48
49 memset(buf, 0, MAX_LEN);
50
51 len_addr = sizeof(remote_addr);
52
53 sock_data = accept(sock_fd, (struct sockaddr *)&remote_addr, (socklen_t *)&len_addr);//接受客戶端的連接
54 if (ret < 0)
55 {
56 perror("accept()");
57 close(sock_fd);
58 return ret;
59 }
60
61 while (1)
62 {
63 int slen;
64 len = recv(sock_data, buf, MAX_LEN, 0);//接受客戶端的數據
65 if (len < 0)
66 {
67 perror("recv()");
68 close(sock_data);
69 close(sock_fd);
70 return len;
71 }
72 printf("%s\n", buf);
73
74 slen = send(sock_data, "congratulation!", 15, 0);//向客戶端發送數據
75 if (slen <= 0)
76 {
77 printf("slen = %d\n", slen);
78 perror("send()");
79 close(sock_data);
80 close(sock_fd);
81 return slen;
82 }
83 sleep(1);
84 }
85
86 close(sock_data);
87 close(sock_fd);
88
89 return 0; }
//客戶端代碼
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/socket.h>
4 #include <unistd.h>
5 #include <netinet/in.h>
6 #include <sys/stat.h>
7 #include <stdlib.h>
8 #include <arpa/inet.h>
9
10 #define REMOTE_PORT 1234
11 #define MAX_LEN 512
12
13 int main(int argc, char *argv[])
14 {
15 int sock_fd, ret;
16 int len;
17 char buf[MAX_LEN];
18 struct sockaddr_in local_addr, remote_addr;
19
20 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
21 if (sock_fd < 0)
22 {
23 perror("socket()");
24 return sock_fd;
25 }
26
28 local_addr.sin_family = AF_INET;
29 local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //自動獲取本機的ip地址
30 local_addr.sin_port = htons(0); //隨機選取可用的埠,並不是指定埠為0
31
33 remote_addr.sin_family= AF_INET;
34 remote_addr.sin_port = htons(REMOTE_PORT);
35 ret = inet_aton("127.0.0.1", &remote_addr.sin_addr);
36
38 ret = bind(sock_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)); //把本機的ip,port和socket綁定
39 if (ret < 0)
40 {
41 perror("bind() !");
42 close(sock_fd);
43 return ret;
44 }
45
47 ret = connect(sock_fd, (struct sockaddr *)&remote_addr, (socklen_t)sizeof(remote_addr)); //把本機的socket和對方的port,ip建立連接
48 if (ret < 0)
49 {
50 perror("connect()");
51 close(sock_fd);
52 return ret;
53 }
54
55 memset(buf, 0, MAX_LEN);
56
57 while (1)
58 {
59 int i;
60 // len = send(sock_fd, buf, (size_t)MAX_LEN, 0);
61 len = send(sock_fd, "hello", 6, 0);
62 if (len <= 0)
63 {
64 perror("send()");
65 close(sock_fd);
66 return ret;
67 }
68
69 // printf("%d-->bytes send!\n", len);
70 sleep(1);
71
72 len = recv(sock_fd, buf, MAX_LEN, 0);
73 if (len <= 0)
74 {
75 perror("recv()");
76 close(sock_fd);
77 return ret;
78 }
79
80 for (i = 0; i < len; i++)
81 {
82 printf("%c", buf[i]);
83 }
84 printf("\n");
85 }
86
87 close(sock_fd);
88
89 return 0;
90 }
Ⅸ linux下socket編程,菜鳥求解。。。
你這個東西問題太多啦,老實說,我那過去編都編不過。我改好了,給你指出幾個重大錯誤!
server:
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include <unistd.h>
#include<fcntl.h>
#include<string.h>
#define IPADDR "127.0.0.1"
#define PORT 21234
const char *logpath = "./log";
int main()
{
struct sockaddr_in servaddr,cliaddr;
int sockfd,clifd,logfd;
socklen_t clilen;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
//bzero(&servaddr,sizeof(servaddr));
sockfd=socket(AF_INET,SOCK_STREAM,0);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(sockfd,8);
printf("aaaaaaaaaaaaaaaa\n");
char buf[500] = {0};
for(;;)
{
clilen = sizeof(cliaddr);
clifd=accept(sockfd,(struct sockaddr *)&cliaddr,&clilen);
printf("%d\n",clifd);
if(clifd < 0)
{
printf("cccccccccccccccccccccc\n");
continue;
}
else
{
printf("dddddddddddddddddddddddd\n");
strcpy(buf,"welcome to 127.0.0.1:21234");
send(clifd,buf,strlen(buf),0);
}
close(clifd);
}
close(sockfd);
return 0;
}
client:
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define PORT 43212
#define SERVPORT 21234
#define SERVADDR "127.0.0.1"
int main()
{
int servfd,clifd,connre;
struct sockaddr_in servaddr,cliaddr;
clifd=socket(AF_INET,SOCK_STREAM,0);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(21234);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//bzero(&servaddr,sizeof(servaddr));
if((connre=connect(clifd,(struct sockaddr *)&servaddr,sizeof(servaddr)))<0)
{
printf("sorry,connect wrong\n");
exit(1);
}
printf("%d\n",connre);
printf("connect ok,waiting for the server's message back\n");
int length;
char buf[500];
while(1)
{
if((length = recv(clifd,buf,500,0))<0)
{
continue;
}
else
{
printf("get it ,get it\n");
break;
}
}
printf("hi,it's the client,I have recieve message :'hello,welcome' from server");
close(clifd);
return 0;
}
/////////////////////////////////
錯誤1:bzero(&servaddr,sizeof(servaddr)); //剛賦值又清0,why?
錯誤2:servaddr.sin_port = htons(PORT);//你要連的是serverport
其他的錯誤懶得說了,自己看吧.累死我了