- 有很多的文章都有介紹socket通信憔足,但是大多都是用了框架执庐。如果是以學(xué)習(xí)為目的來(lái)用的話酪耕,是十分不利的。所以還是有必要寫(xiě)篇文章來(lái)介紹一下轨淌。
server in mac
client in mac
服務(wù)器的代碼:
1.設(shè)置socket迂烁,設(shè)置好端口號(hào)看尼,地址,長(zhǎng)度盟步。
-最重要的是要調(diào)用bind()函數(shù)對(duì)socket進(jìn)行綁定藏斩;
2.綁定成功后success為YES,進(jìn)入第二步却盘,調(diào)用listen()開(kāi)始監(jiān)聽(tīng)
3.如果有客戶端連接到了服務(wù)器狰域,進(jìn)入第三步。
-注意每個(gè)客戶端連接服務(wù)器后黄橘,服務(wù)器都會(huì)分配一個(gè)端口給客戶端兆览,并在這個(gè)端口上進(jìn)行通信。然后服務(wù)器繼續(xù)在設(shè)定的端口上繼續(xù)等待塞关。
所以在控制臺(tái)上顯示的端口號(hào)并不是你所設(shè)定的(17777)抬探。而是系統(tǒng)自定分配的。(如果沒(méi)有對(duì)socket有比較好的了解描孟,這里很容易會(huì)沒(méi)注意到)
#import
#include<sys/types.h>
#include<sys/socket.h>
#include <sys/xattr.h>
#include<arpa/inet.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
int err;
int fd=socket(AF_INET, SOCK_STREAM , 0);
BOOL success=(fd!=-1);
// 1
if (success) {
NSLog(@"socket success");
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));//初始化socket
addr.sin_len=sizeof(addr);//socket字節(jié)長(zhǎng)度
addr.sin_family=AF_INET; //協(xié)議族
addr.sin_port=htons(17777); //端口
addr.sin_addr.s_addr=INADDR_ANY; //設(shè)定地址為 所有地址 本地網(wǎng)卡:回環(huán)網(wǎng)卡驶睦,。匿醒。场航。 無(wú)線網(wǎng)卡
err=bind(fd, (const struct sockaddr *)&addr, sizeof(addr));
success=(err==0);
}
// 2
//
if (success) {
NSLog(@"bind(綁定) success");
err=listen(fd, 5);//開(kāi)始監(jiān)聽(tīng)
success=(err==0);
}
//3
#warning 每個(gè)客戶端連接服務(wù)器后,服務(wù)器都會(huì)分配一個(gè)端口給客戶端廉羔,然后服務(wù)器繼續(xù)在設(shè)定的端口上繼續(xù)等待溉痢。
if (success) {
NSLog(@"listen success");
while (true) {
struct sockaddr_in peeraddr;
int peerfd;
socklen_t addrLen;
addrLen=sizeof(peeraddr);
NSLog(@"prepare accept");
//獲得服務(wù)器和當(dāng)前連接客戶端通信的專(zhuān)用socket。
peerfd=accept(fd, (struct sockaddr *)&peeraddr, &addrLen);
success=(peerfd!=-1);
if (success) {
NSLog(@"accept success,remote address:%s,port:%d",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
char buf[1024];
ssize_t count;
size_t len=sizeof(buf);
do {
count=recv(peerfd, buf, len, 0);
NSString* str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
NSLog(@"%@",str);
} while (strcmp(buf, "exit")!=0);
}
close(peerfd);
}
}
}
return 0;
}
客戶端的代碼
1.值得注意的就是客戶端中并不需要綁定socket憋他。
#include<sys/types.h>
#include<sys/socket.h>
#include <sys/xattr.h>
#include<arpa/inet.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
int err;
int fd=socket(AF_INET, SOCK_STREAM, 0);
BOOL success=(fd!=-1);
struct sockaddr_in addr;
#warning 在客戶端中孩饼,是不用綁定端口的。
// if (success) {
// NSLog(@"socket success");
// memset(&addr, 0, sizeof(addr));
// addr.sin_len=sizeof(addr);
// addr.sin_family=AF_INET;
// addr.sin_addr.s_addr=INADDR_ANY;
// err=bind(fd, (const struct sockaddr *)&addr, sizeof(addr));
// success=(err==0);
// }
if (success) {
struct sockaddr_in peeraddr;
memset(&peeraddr, 0, sizeof(peeraddr));
peeraddr.sin_len=sizeof(peeraddr);
peeraddr.sin_family=AF_INET;
peeraddr.sin_port=htons(17777);
// peeraddr.sin_addr.s_addr=INADDR_ANY;
peeraddr.sin_addr.s_addr=inet_addr("127.0.0.1");
// 這個(gè)地址是服務(wù)器的地址竹挡,
socklen_t addrLen;
addrLen =sizeof(peeraddr);
NSLog(@"connecting");
err=connect(fd, (struct sockaddr *)&peeraddr, addrLen);
success=(err==0);
if (success) {
// struct sockaddr_in addr;
err =getsockname(fd, (struct sockaddr *)&addr, &addrLen);
success=(err==0);
if (success) {
NSLog(@"connect success,local address:%s,port:%d",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
char buf[1024];
do {
printf("input message:");
scanf("%s",buf);
send(fd, buf, 1024, 0);
} while (strcmp(buf, "exit")!=0);
}
}
else{
NSLog(@"connect failed");
}
}
}
return 0;
}